/* -*- c -*- */

#ifndef _MULTIARRAYMODULE
#define _MULTIARRAYMODULE
#endif
#include "numpy/arrayscalars.h"

#include "config.h"
#include "numpyos.c"

static PyBoolScalarObject _PyArrayScalar_BoolValues[2] = {
    {PyObject_HEAD_INIT(&PyBoolArrType_Type) 0},
    {PyObject_HEAD_INIT(&PyBoolArrType_Type) 1},
};

/*
 * Inheritance is established later when tp_bases is set (or tp_base for
 * single inheritance)
 */

/**begin repeat
 * #name = number, integer, signedinteger, unsignedinteger, inexact,
 *         floating, complexfloating, flexible, character#
 * #NAME = Number, Integer, SignedInteger, UnsignedInteger, Inexact,
 *         Floating, ComplexFloating, Flexible, Character#
 */
static PyTypeObject Py@NAME@ArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.@name@",                              /* tp_name*/
    sizeof(PyObject),                            /* tp_basicsize*/
    0,                                           /* tp_itemsize */
    /* methods */
    0,                                           /* tp_dealloc */
    0,                                           /* tp_print */
    0,                                           /* tp_getattr */
    0,                                           /* tp_setattr */
    0,                                           /* tp_compare */
    0,                                           /* tp_repr */
    0,                                           /* tp_as_number */
    0,                                           /* tp_as_sequence */
    0,                                           /* tp_as_mapping */
    0,                                           /* tp_hash */
    0,                                           /* tp_call */
    0,                                           /* tp_str */
    0,                                           /* tp_getattro */
    0,                                           /* tp_setattro */
    0,                                           /* tp_as_buffer */
    0,                                           /* tp_flags */
    0,                                           /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */

#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};
/**end repeat**/

static void *
scalar_value(PyObject *scalar, PyArray_Descr *descr)
{
    int type_num;
    int align;
    intp memloc;
    if (descr == NULL) {
        descr = PyArray_DescrFromScalar(scalar);
        type_num = descr->type_num;
        Py_DECREF(descr);
    }
    else {
        type_num = descr->type_num;
    }
    switch (type_num) {
#define CASE(ut,lt) case NPY_##ut: return &(((Py##lt##ScalarObject *)scalar)->obval)
        CASE(BOOL, Bool);
        CASE(BYTE, Byte);
        CASE(UBYTE, UByte);
        CASE(SHORT, Short);
        CASE(USHORT, UShort);
        CASE(INT, Int);
        CASE(UINT, UInt);
        CASE(LONG, Long);
        CASE(ULONG, ULong);
        CASE(LONGLONG, LongLong);
        CASE(ULONGLONG, ULongLong);
        CASE(FLOAT, Float);
        CASE(DOUBLE, Double);
        CASE(LONGDOUBLE, LongDouble);
        CASE(CFLOAT, CFloat);
        CASE(CDOUBLE, CDouble);
        CASE(CLONGDOUBLE, CLongDouble);
        CASE(OBJECT, Object);
#undef CASE
        case NPY_STRING:
            return (void *)PyString_AS_STRING(scalar);
        case NPY_UNICODE:
            return (void *)PyUnicode_AS_DATA(scalar);
        case NPY_VOID:
            return ((PyVoidScalarObject *)scalar)->obval;
    }

    /*
     * Must be a user-defined type --- check to see which
     * scalar it inherits from.
     */

#define _CHK(cls) (PyObject_IsInstance(scalar, \
            (PyObject *)&Py##cls##ArrType_Type))
#define _OBJ(lt) &(((Py##lt##ScalarObject *)scalar)->obval)
#define _IFCASE(cls) if _CHK(cls) return _OBJ(cls)

    if _CHK(Number) {
        if _CHK(Integer) {
            if _CHK(SignedInteger) {
                _IFCASE(Byte);
                _IFCASE(Short);
                _IFCASE(Int);
                _IFCASE(Long);
                _IFCASE(LongLong);
            }
            else {
                /* Unsigned Integer */
                _IFCASE(UByte);
                _IFCASE(UShort);
                _IFCASE(UInt);
                _IFCASE(ULong);
                _IFCASE(ULongLong);
            }
        }
        else {
            /* Inexact */
            if _CHK(Floating) {
                _IFCASE(Float);
                _IFCASE(Double);
                _IFCASE(LongDouble);
            }
            else {
                /*ComplexFloating */
                _IFCASE(CFloat);
                _IFCASE(CDouble);
                _IFCASE(CLongDouble);
            }
        }
    }
    else if (_CHK(Bool)) {
        return _OBJ(Bool);
    }
    else if (_CHK(Flexible)) {
        if (_CHK(String)) {
            return (void *)PyString_AS_STRING(scalar);
        }
        if (_CHK(Unicode)) {
            return (void *)PyUnicode_AS_DATA(scalar);
        }
        if (_CHK(Void)) {
            return ((PyVoidScalarObject *)scalar)->obval;
        }
    }
    else {
        _IFCASE(Object);
    }


    /*
     * Use the alignment flag to figure out where the data begins
     * after a PyObject_HEAD
     */
    memloc = (intp)scalar;
    memloc += sizeof(PyObject);
    /* now round-up to the nearest alignment value */
    align = descr->alignment;
    if (align > 1) {
        memloc = ((memloc + align - 1)/align)*align;
    }
    return (void *)memloc;
#undef _IFCASE
#undef _OBJ
#undef _CHK
}

/*NUMPY_API
 * Convert to c-type
 *
 * no error checking is performed -- ctypeptr must be same type as scalar
 * in case of flexible type, the data is not copied
 * into ctypeptr which is expected to be a pointer to pointer
 */
static void
PyArray_ScalarAsCtype(PyObject *scalar, void *ctypeptr)
{
    PyArray_Descr *typecode;
    void *newptr;
    typecode = PyArray_DescrFromScalar(scalar);
    newptr = scalar_value(scalar, typecode);

    if (PyTypeNum_ISEXTENDED(typecode->type_num)) {
        void **ct = (void **)ctypeptr;
        *ct = newptr;
    }
    else {
        memcpy(ctypeptr, newptr, typecode->elsize);
    }
    Py_DECREF(typecode);
    return;
}

/*NUMPY_API
 * Cast Scalar to c-type
 *
 * The output buffer must be large-enough to receive the value
 *  Even for flexible types which is different from ScalarAsCtype
 *  where only a reference for flexible types is returned
 *
 * This may not work right on narrow builds for NumPy unicode scalars.
 */
static int
PyArray_CastScalarToCtype(PyObject *scalar, void *ctypeptr,
                          PyArray_Descr *outcode)
{
    PyArray_Descr* descr;
    PyArray_VectorUnaryFunc* castfunc;

    descr = PyArray_DescrFromScalar(scalar);
    castfunc = PyArray_GetCastFunc(descr, outcode->type_num);
    if (castfunc == NULL) {
        return -1;
    }
    if (PyTypeNum_ISEXTENDED(descr->type_num) ||
            PyTypeNum_ISEXTENDED(outcode->type_num)) {
        PyArrayObject *ain, *aout;

        ain = (PyArrayObject *)PyArray_FromScalar(scalar, NULL);
        if (ain == NULL) {
            Py_DECREF(descr);
            return -1;
        }
        aout = (PyArrayObject *)
            PyArray_NewFromDescr(&PyArray_Type,
                    outcode,
                    0, NULL,
                    NULL, ctypeptr,
                    CARRAY, NULL);
        if (aout == NULL) {
            Py_DECREF(ain);
            return -1;
        }
        castfunc(ain->data, aout->data, 1, ain, aout);
        Py_DECREF(ain);
        Py_DECREF(aout);
    }
    else {
        castfunc(scalar_value(scalar, descr), ctypeptr, 1, NULL, NULL);
    }
    Py_DECREF(descr);
    return 0;
}

/*NUMPY_API
 * Cast Scalar to c-type
 */
static int
PyArray_CastScalarDirect(PyObject *scalar, PyArray_Descr *indescr,
                         void *ctypeptr, int outtype)
{
    PyArray_VectorUnaryFunc* castfunc;
    void *ptr;
    castfunc = PyArray_GetCastFunc(indescr, outtype);
    if (castfunc == NULL) {
        return -1;
    }
    ptr = scalar_value(scalar, indescr);
    castfunc(ptr, ctypeptr, 1, NULL, NULL);
    return 0;
}

/*NUMPY_API
 * Get 0-dim array from scalar
 *
 * 0-dim array from array-scalar object
 * always contains a copy of the data
 * unless outcode is NULL, it is of void type and the referrer does
 * not own it either.
 *
 * steals reference to outcode
 */
static PyObject *
PyArray_FromScalar(PyObject *scalar, PyArray_Descr *outcode)
{
    PyArray_Descr *typecode;
    PyObject *r;
    char *memptr;
    PyObject *ret;

    /* convert to 0-dim array of scalar typecode */
    typecode = PyArray_DescrFromScalar(scalar);
    if ((typecode->type_num == PyArray_VOID) &&
            !(((PyVoidScalarObject *)scalar)->flags & OWNDATA) &&
            outcode == NULL) {
        r = PyArray_NewFromDescr(&PyArray_Type,
                typecode,
                0, NULL, NULL,
                ((PyVoidScalarObject *)scalar)->obval,
                ((PyVoidScalarObject *)scalar)->flags,
                NULL);
        PyArray_BASE(r) = (PyObject *)scalar;
        Py_INCREF(scalar);
        return r;
    }
    r = PyArray_NewFromDescr(&PyArray_Type,
            typecode,
            0, NULL,
            NULL, NULL, 0, NULL);
    if (r==NULL) {
        Py_XDECREF(outcode);
        return NULL;
    }
    if (PyDataType_FLAGCHK(typecode, NPY_USE_SETITEM)) {
        if (typecode->f->setitem(scalar, PyArray_DATA(r), r) < 0) {
            Py_XDECREF(outcode); Py_DECREF(r);
            return NULL;
        }
        goto finish;
    }

    memptr = scalar_value(scalar, typecode);

#ifndef Py_UNICODE_WIDE
    if (typecode->type_num == PyArray_UNICODE) {
        PyUCS2Buffer_AsUCS4((Py_UNICODE *)memptr,
                (PyArray_UCS4 *)PyArray_DATA(r),
                PyUnicode_GET_SIZE(scalar),
                PyArray_ITEMSIZE(r) >> 2);
    }
    else
#endif
    {
        memcpy(PyArray_DATA(r), memptr, PyArray_ITEMSIZE(r));
        if (PyDataType_FLAGCHK(typecode, NPY_ITEM_HASOBJECT)) {
            Py_INCREF(*((PyObject **)memptr));
        }
    }

finish:
    if (outcode == NULL) {
        return r;
    }
    if (outcode->type_num == typecode->type_num) {
        if (!PyTypeNum_ISEXTENDED(typecode->type_num) ||
                (outcode->elsize == typecode->elsize))
            return r;
    }

    /* cast if necessary to desired output typecode */
    ret = PyArray_CastToType((PyArrayObject *)r, outcode, 0);
    Py_DECREF(r);
    return ret;
}

/*NUMPY_API
 * Get an Array Scalar From a Python Object
 *
 * Returns NULL if unsuccessful but error is only set if another error occurred.
 * Currently only Numeric-like object supported.
 */
static PyObject *
PyArray_ScalarFromObject(PyObject *object)
{
    PyObject *ret=NULL;
    if (PyArray_IsZeroDim(object)) {
        return PyArray_ToScalar(PyArray_DATA(object), object);
    }
    if (PyInt_Check(object)) {
        ret = PyArrayScalar_New(Long);
        if (ret == NULL) {
            return NULL;
        }
        PyArrayScalar_VAL(ret, Long) = PyInt_AS_LONG(object);
    }
    else if (PyFloat_Check(object)) {
        ret = PyArrayScalar_New(Double);
        if (ret == NULL) {
            return NULL;
        }
        PyArrayScalar_VAL(ret, Double) = PyFloat_AS_DOUBLE(object);
    }
    else if (PyComplex_Check(object)) {
        ret = PyArrayScalar_New(CDouble);
        if (ret == NULL) {
            return NULL;
        }
        PyArrayScalar_VAL(ret, CDouble).real =
                ((PyComplexObject *)object)->cval.real;
        PyArrayScalar_VAL(ret, CDouble).imag =
                ((PyComplexObject *)object)->cval.imag;
    }
    else if (PyLong_Check(object)) {
        longlong val;
        val = PyLong_AsLongLong(object);
        if (val==-1 && PyErr_Occurred()) {
            PyErr_Clear();
            return NULL;
        }
        ret = PyArrayScalar_New(LongLong);
        if (ret == NULL) {
            return NULL;
        }
        PyArrayScalar_VAL(ret, LongLong) = val;
    }
    else if (PyBool_Check(object)) {
        if (object == Py_True) {
            PyArrayScalar_RETURN_TRUE;
        }
        else {
            PyArrayScalar_RETURN_FALSE;
        }
    }
    return ret;
}


static PyObject *
gentype_alloc(PyTypeObject *type, Py_ssize_t nitems)
{
    PyObject *obj;
    const size_t size = _PyObject_VAR_SIZE(type, nitems + 1);

    obj = (PyObject *)_pya_malloc(size);
    memset(obj, 0, size);
    if (type->tp_itemsize == 0) {
        PyObject_INIT(obj, type);
    }
    else {
        (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
    }
    return obj;
}

static void
gentype_dealloc(PyObject *v)
{
    v->ob_type->tp_free(v);
}


static PyObject *
gentype_power(PyObject *m1, PyObject *m2, PyObject *NPY_UNUSED(m3))
{
    PyObject *arr, *ret, *arg2;
    char *msg="unsupported operand type(s) for ** or pow()";

    if (!PyArray_IsScalar(m1,Generic)) {
        if (PyArray_Check(m1)) {
            ret = m1->ob_type->tp_as_number->nb_power(m1,m2, Py_None);
        }
        else {
            if (!PyArray_IsScalar(m2,Generic)) {
                PyErr_SetString(PyExc_TypeError, msg);
                return NULL;
            }
            arr = PyArray_FromScalar(m2, NULL);
            if (arr == NULL) {
                return NULL;
            }
            ret = arr->ob_type->tp_as_number->nb_power(m1, arr, Py_None);
            Py_DECREF(arr);
        }
        return ret;
    }
    if (!PyArray_IsScalar(m2, Generic)) {
        if (PyArray_Check(m2)) {
            ret = m2->ob_type->tp_as_number->nb_power(m1,m2, Py_None);
        }
        else {
            if (!PyArray_IsScalar(m1, Generic)) {
                PyErr_SetString(PyExc_TypeError, msg);
                return NULL;
            }
            arr = PyArray_FromScalar(m1, NULL);
            if (arr == NULL) {
                return NULL;
            }
            ret = arr->ob_type->tp_as_number->nb_power(arr, m2, Py_None);
            Py_DECREF(arr);
        }
        return ret;
    }
    arr = arg2 = NULL;
    arr = PyArray_FromScalar(m1, NULL);
    arg2 = PyArray_FromScalar(m2, NULL);
    if (arr == NULL || arg2 == NULL) {
        Py_XDECREF(arr);
        Py_XDECREF(arg2);
        return NULL;
    }
    ret = arr->ob_type->tp_as_number->nb_power(arr, arg2, Py_None);
    Py_DECREF(arr);
    Py_DECREF(arg2);
    return ret;
}

static PyObject *
gentype_generic_method(PyObject *self, PyObject *args, PyObject *kwds,
        char *str)
{
    PyObject *arr, *meth, *ret;

    arr = PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    meth = PyObject_GetAttrString(arr, str);
    if (meth == NULL) {
        Py_DECREF(arr);
        return NULL;
    }
    if (kwds == NULL) {
        ret = PyObject_CallObject(meth, args);
    }
    else {
        ret = PyObject_Call(meth, args, kwds);
    }
    Py_DECREF(meth);
    Py_DECREF(arr);
    if (ret && PyArray_Check(ret)) {
        return PyArray_Return((PyArrayObject *)ret);
    }
    else {
        return ret;
    }
}

/**begin repeat
 *
 * #name = add, subtract, divide, remainder, divmod, lshift, rshift,
 *         and, xor, or, floor_divide, true_divide#
 */
static PyObject *
gentype_@name@(PyObject *m1, PyObject *m2)
{
    return PyArray_Type.tp_as_number->nb_@name@(m1, m2);
}

/**end repeat**/


static PyObject *
gentype_multiply(PyObject *m1, PyObject *m2)
{
    PyObject *ret = NULL;
    long repeat;

    if (!PyArray_IsScalar(m1, Generic) &&
            ((m1->ob_type->tp_as_number == NULL) ||
             (m1->ob_type->tp_as_number->nb_multiply == NULL))) {
        /* Try to convert m2 to an int and try sequence repeat */
        repeat = PyInt_AsLong(m2);
        if (repeat == -1 && PyErr_Occurred()) {
            return NULL;
        }
        ret = PySequence_Repeat(m1, (int) repeat);
    }
    else if (!PyArray_IsScalar(m2, Generic) &&
            ((m2->ob_type->tp_as_number == NULL) ||
             (m2->ob_type->tp_as_number->nb_multiply == NULL))) {
        /* Try to convert m1 to an int and try sequence repeat */
        repeat = PyInt_AsLong(m1);
        if (repeat == -1 && PyErr_Occurred()) {
            return NULL;
        }
        ret = PySequence_Repeat(m2, (int) repeat);
    }
    if (ret == NULL) {
        PyErr_Clear(); /* no effect if not set */
        ret = PyArray_Type.tp_as_number->nb_multiply(m1, m2);
    }
    return ret;
}

/**begin repeat
 *
 * #name=positive, negative, absolute, invert, int, long, float, oct, hex#
 */
static PyObject *
gentype_@name@(PyObject *m1)
{
    PyObject *arr, *ret;

    arr = PyArray_FromScalar(m1, NULL);
    if (arr == NULL) {
        return NULL;
    }
    ret = arr->ob_type->tp_as_number->nb_@name@(arr);
    Py_DECREF(arr);
    return ret;
}
/**end repeat**/

static int
gentype_nonzero_number(PyObject *m1)
{
    PyObject *arr;
    int ret;

    arr = PyArray_FromScalar(m1, NULL);
    if (arr == NULL) {
        return -1;
    }
    ret = arr->ob_type->tp_as_number->nb_nonzero(arr);
    Py_DECREF(arr);
    return ret;
}

static PyObject *
gentype_str(PyObject *self)
{
    PyArrayObject *arr;
    PyObject *ret;

    arr = (PyArrayObject *)PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    ret = PyObject_Str((PyObject *)arr);
    Py_DECREF(arr);
    return ret;
}


static PyObject *
gentype_repr(PyObject *self)
{
    PyArrayObject *arr;
    PyObject *ret;

    arr = (PyArrayObject *)PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    ret = PyObject_Str((PyObject *)arr);
    Py_DECREF(arr);
    return ret;
}

#ifdef FORCE_NO_LONG_DOUBLE_FORMATTING
#undef NPY_LONGDOUBLE_FMT
#define NPY_LONGDOUBLE_FMT NPY_DOUBLE_FMT
#endif

/**begin repeat
 * #name = float, double, longdouble#
 * #NAME = FLOAT, DOUBLE, LONGDOUBLE#
 * #type = f, d, l#
 */

#define _FMT1 "%%.%i" NPY_@NAME@_FMT
#define _FMT2 "%%+.%i" NPY_@NAME@_FMT

static void
format_@name@(char *buf, size_t buflen, @name@ val, unsigned int prec)
{
    /* XXX: Find a correct size here for format string */
    char format[64], *res;
    size_t i, cnt;

    PyOS_snprintf(format, sizeof(format), _FMT1, prec);
    res = NumPyOS_ascii_format@type@(buf, buflen, format, val, 0);
    if (res == NULL) {
        fprintf(stderr, "Error while formatting\n");
        return;
    }

    /* If nothing but digits after sign, append ".0" */
    cnt = strlen(buf);
    for (i = (val < 0) ? 1 : 0; i < cnt; ++i) {
        if (!isdigit(Py_CHARMASK(buf[i]))) {
            break;
        }
    }
    if (i == cnt && buflen >= cnt + 3) {
        strcpy(&buf[cnt],".0");
    }
}

static void
format_c@name@(char *buf, size_t buflen, c@name@ val, unsigned int prec)
{
    /* XXX: Find a correct size here for format string */
    char format[64];
    char *res;

    /*
     * Ideally, we should handle this nan/inf stuff in NumpyOS_ascii_format*
     */
    if (val.real == 0.0) {
        PyOS_snprintf(format, sizeof(format), _FMT1, prec);
        res = NumPyOS_ascii_format@type@(buf, buflen-1, format, val.imag, 0);
        if (res == NULL) {
            fprintf(stderr, "Error while formatting\n");
            return;
        }
#if PY_VERSION_HEX >= 0x02060000
        if (!npy_isfinite(val.imag)) {
            strncat(buf, "*", 1);
        }
#endif
        strncat(buf, "j", 1);
    }
    else {
        char re[64], im[64];
	if (npy_isfinite(val.real)) {
		PyOS_snprintf(format, sizeof(format), _FMT1, prec);
		res = NumPyOS_ascii_format@type@(re, sizeof(re), format, val.real, 0);
		if (res == NULL) {
		    fprintf(stderr, "Error while formatting\n");
		    return;
		}
	} else {
		if (npy_isnan(val.real)) {
			strcpy(re, "nan");
		} else if (val.real > 0){
			strcpy(re, "inf");
		} else {
			strcpy(re, "-inf");
		}
	}


	if (npy_isfinite(val.imag)) {
		PyOS_snprintf(format, sizeof(format), _FMT2, prec);
		res = NumPyOS_ascii_format@type@(im, sizeof(im), format, val.imag, 0);
		if (res == NULL) {
		    fprintf(stderr, "Error while formatting\n");
		    return;
		}
	} else {
		if (npy_isnan(val.imag)) {
			strcpy(im, "+nan");
		} else if (val.imag > 0){
			strcpy(im, "+inf");
		} else {
			strcpy(im, "-inf");
		}
                #if PY_VERSION_HEX >= 0x02060000
                if (!npy_isfinite(val.imag)) {
                        strncat(im, "*", 1);
                }
                #endif
	}
        PyOS_snprintf(buf, buflen, "(%s%sj)", re, im);
    }
}

#undef _FMT1
#undef _FMT2

/**end repeat**/

/*
 * over-ride repr and str of array-scalar strings and unicode to
 * remove NULL bytes and then call the corresponding functions
 * of string and unicode.
 */

/**begin repeat
 * #name = string*2,unicode*2#
 * #form = (repr,str)*2#
 * #Name = String*2,Unicode*2#
 * #NAME = STRING*2,UNICODE*2#
 * #extra = AndSize*2,,#
 * #type = char*2, Py_UNICODE*2#
 */
static PyObject *
@name@type_@form@(PyObject *self)
{
    const @type@ *dptr, *ip;
    int len;
    PyObject *new;
    PyObject *ret;

    ip = dptr = Py@Name@_AS_@NAME@(self);
    len = Py@Name@_GET_SIZE(self);
    dptr += len-1;
    while(len > 0 && *dptr-- == 0) {
        len--;
    }
    new = Py@Name@_From@Name@@extra@(ip, len);
    if (new == NULL) {
        return PyString_FromString("");
    }
    ret = Py@Name@_Type.tp_@form@(new);
    Py_DECREF(new);
    return ret;
}
/**end repeat**/

/* These values are finfo.precision + 2 */
#define FLOATPREC_REPR 8
#define FLOATPREC_STR 6
#define DOUBLEPREC_REPR 17
#define DOUBLEPREC_STR 12
#if SIZEOF_LONGDOUBLE == SIZEOF_DOUBLE
#define LONGDOUBLEPREC_REPR DOUBLEPREC_REPR
#define LONGDOUBLEPREC_STR DOUBLEPREC_STR
#else /* More than probably needed on Intel FP */
#define LONGDOUBLEPREC_REPR 20
#define LONGDOUBLEPREC_STR 12
#endif

/*
 * float type str and repr
 *
 * These functions will return NULL if PyString creation fails.
 */

/**begin repeat
 * #name = float, double, longdouble#
 * #Name = Float, Double, LongDouble#
 * #NAME = FLOAT, DOUBLE, LONGDOUBLE#
 */
/**begin repeat1
 * #kind = str, repr#
 * #KIND = STR, REPR#
 */

#define PREC @NAME@PREC_@KIND@

static PyObject *
@name@type_@kind@(PyObject *self)
{
    char buf[100];
    @name@ val = ((Py@Name@ScalarObject *)self)->obval;

    format_@name@(buf, sizeof(buf), val, PREC);
    return PyString_FromString(buf);
}

static PyObject *
c@name@type_@kind@(PyObject *self)
{
    char buf[202];
    c@name@ val = ((PyC@Name@ScalarObject *)self)->obval;

    format_c@name@(buf, sizeof(buf), val, PREC);
    return PyString_FromString(buf);
}

#undef PREC

/**end repeat1**/
/**end repeat**/

/*
 * float type print (control print a, where a is a float type instance)
 */
/**begin repeat
 * #name = float, double, longdouble#
 * #Name = Float, Double, LongDouble#
 * #NAME = FLOAT, DOUBLE, LONGDOUBLE#
 */

static int
@name@type_print(PyObject *v, FILE *fp, int flags)
{
        char buf[100];
        @name@ val = ((Py@Name@ScalarObject *)v)->obval;

        format_@name@(buf, sizeof(buf), val,
                      (flags & Py_PRINT_RAW) ? @NAME@PREC_STR : @NAME@PREC_REPR);
        Py_BEGIN_ALLOW_THREADS
        fputs(buf, fp);
        Py_END_ALLOW_THREADS
        return 0;
}

static int
c@name@type_print(PyObject *v, FILE *fp, int flags)
{
        /* Size of buf: twice sizeof(real) + 2 (for the parenthesis) */
        char buf[202];
        c@name@ val = ((PyC@Name@ScalarObject *)v)->obval;

        format_c@name@(buf, sizeof(buf), val,
                       (flags & Py_PRINT_RAW) ? @NAME@PREC_STR : @NAME@PREC_REPR);
        Py_BEGIN_ALLOW_THREADS
        fputs(buf, fp);
        Py_END_ALLOW_THREADS
        return 0;
}

/**end repeat**/


/*
 * Could improve this with a PyLong_FromLongDouble(longdouble ldval)
 * but this would need some more work...
 */

/**begin repeat
 *
 * #name = (int, long, hex, oct, float)*2#
 * #KIND = (Long*4, Float)*2#
 * #char = ,,,,,c*5#
 * #CHAR = ,,,,,C*5#
 * #POST = ,,,,,.real*5#
 */
static PyObject *
@char@longdoubletype_@name@(PyObject *self)
{
    double dval;
    PyObject *obj, *ret;

    dval = (double)(((Py@CHAR@LongDoubleScalarObject *)self)->obval)@POST@;
    obj = Py@KIND@_FromDouble(dval);
    ret = obj->ob_type->tp_as_number->nb_@name@(obj);
    Py_DECREF(obj);
    return ret;
}
/**end repeat**/


static PyNumberMethods gentype_as_number = {
    (binaryfunc)gentype_add,                     /*nb_add*/
    (binaryfunc)gentype_subtract,                /*nb_subtract*/
    (binaryfunc)gentype_multiply,                /*nb_multiply*/
    (binaryfunc)gentype_divide,                  /*nb_divide*/
    (binaryfunc)gentype_remainder,               /*nb_remainder*/
    (binaryfunc)gentype_divmod,                  /*nb_divmod*/
    (ternaryfunc)gentype_power,                  /*nb_power*/
    (unaryfunc)gentype_negative,
    (unaryfunc)gentype_positive,                 /*nb_pos*/
    (unaryfunc)gentype_absolute,                 /*(unaryfunc)gentype_abs,*/
    (inquiry)gentype_nonzero_number,             /*nb_nonzero*/
    (unaryfunc)gentype_invert,                   /*nb_invert*/
    (binaryfunc)gentype_lshift,                  /*nb_lshift*/
    (binaryfunc)gentype_rshift,                  /*nb_rshift*/
    (binaryfunc)gentype_and,                     /*nb_and*/
    (binaryfunc)gentype_xor,                     /*nb_xor*/
    (binaryfunc)gentype_or,                      /*nb_or*/
    0,                                           /*nb_coerce*/
    (unaryfunc)gentype_int,                      /*nb_int*/
    (unaryfunc)gentype_long,                     /*nb_long*/
    (unaryfunc)gentype_float,                    /*nb_float*/
    (unaryfunc)gentype_oct,                      /*nb_oct*/
    (unaryfunc)gentype_hex,                      /*nb_hex*/
    0,                                           /*inplace_add*/
    0,                                           /*inplace_subtract*/
    0,                                           /*inplace_multiply*/
    0,                                           /*inplace_divide*/
    0,                                           /*inplace_remainder*/
    0,                                           /*inplace_power*/
    0,                                           /*inplace_lshift*/
    0,                                           /*inplace_rshift*/
    0,                                           /*inplace_and*/
    0,                                           /*inplace_xor*/
    0,                                           /*inplace_or*/
    (binaryfunc)gentype_floor_divide,            /*nb_floor_divide*/
    (binaryfunc)gentype_true_divide,             /*nb_true_divide*/
    0,                                           /*nb_inplace_floor_divide*/
    0,                                           /*nb_inplace_true_divide*/
#if PY_VERSION_HEX >= 0x02050000
    (unaryfunc)NULL,                             /*nb_index*/
#endif
};


static PyObject *
gentype_richcompare(PyObject *self, PyObject *other, int cmp_op)
{
    PyObject *arr, *ret;

    arr = PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    ret = arr->ob_type->tp_richcompare(arr, other, cmp_op);
    Py_DECREF(arr);
    return ret;
}

static PyObject *
gentype_ndim_get(PyObject *NPY_UNUSED(self))
{
    return PyInt_FromLong(0);
}

static PyObject *
gentype_flags_get(PyObject *NPY_UNUSED(self))
{
    return PyArray_NewFlagsObject(NULL);
}

static PyObject *
voidtype_flags_get(PyVoidScalarObject *self)
{
    PyObject *flagobj;
    flagobj = PyArrayFlags_Type.tp_alloc(&PyArrayFlags_Type, 0);
    if (flagobj == NULL) {
        return NULL;
    }
    ((PyArrayFlagsObject *)flagobj)->arr = NULL;
    ((PyArrayFlagsObject *)flagobj)->flags = self->flags;
    return flagobj;
}

static PyObject *
voidtype_dtypedescr_get(PyVoidScalarObject *self)
{
    Py_INCREF(self->descr);
    return (PyObject *)self->descr;
}


static PyObject *
gentype_data_get(PyObject *self)
{
    return PyBuffer_FromObject(self, 0, Py_END_OF_BUFFER);
}


static PyObject *
gentype_itemsize_get(PyObject *self)
{
    PyArray_Descr *typecode;
    PyObject *ret;
    int elsize;

    typecode = PyArray_DescrFromScalar(self);
    elsize = typecode->elsize;
#ifndef Py_UNICODE_WIDE
    if (typecode->type_num == NPY_UNICODE) {
        elsize >>= 1;
    }
#endif
    ret = PyInt_FromLong((long) elsize);
    Py_DECREF(typecode);
    return ret;
}

static PyObject *
gentype_size_get(PyObject *NPY_UNUSED(self))
{
    return PyInt_FromLong(1);
}

static void
gentype_struct_free(void *ptr, void *arg)
{
    PyArrayInterface *arrif = (PyArrayInterface *)ptr;
    Py_DECREF((PyObject *)arg);
    Py_XDECREF(arrif->descr);
    _pya_free(arrif->shape);
    _pya_free(arrif);
}

static PyObject *
gentype_struct_get(PyObject *self)
{
    PyArrayObject *arr;
    PyArrayInterface *inter;

    arr = (PyArrayObject *)PyArray_FromScalar(self, NULL);
    inter = (PyArrayInterface *)_pya_malloc(sizeof(PyArrayInterface));
    inter->two = 2;
    inter->nd = 0;
    inter->flags = arr->flags;
    inter->flags &= ~(UPDATEIFCOPY | OWNDATA);
    inter->flags |= NPY_NOTSWAPPED;
    inter->typekind = arr->descr->kind;
    inter->itemsize = arr->descr->elsize;
    inter->strides = NULL;
    inter->shape = NULL;
    inter->data = arr->data;
    inter->descr = NULL;

    return PyCObject_FromVoidPtrAndDesc(inter, arr, gentype_struct_free);
}

static PyObject *
gentype_priority_get(PyObject *NPY_UNUSED(self))
{
    return PyFloat_FromDouble(NPY_SCALAR_PRIORITY);
}

static PyObject *
gentype_shape_get(PyObject *NPY_UNUSED(self))
{
    return PyTuple_New(0);
}


static PyObject *
gentype_interface_get(PyObject *self)
{
    PyArrayObject *arr;
    PyObject *inter;

    arr = (PyArrayObject *)PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    inter = PyObject_GetAttrString((PyObject *)arr, "__array_interface__");
    if (inter != NULL) {
        PyDict_SetItemString(inter, "__ref", (PyObject *)arr);
    }
    Py_DECREF(arr);
    return inter;
}



static PyObject *
gentype_typedescr_get(PyObject *self)
{
    return (PyObject *)PyArray_DescrFromScalar(self);
}


static PyObject *
gentype_base_get(PyObject *NPY_UNUSED(self))
{
    Py_INCREF(Py_None);
    return Py_None;
}


static PyArray_Descr *
_realdescr_fromcomplexscalar(PyObject *self, int *typenum)
{
    if (PyArray_IsScalar(self, CDouble)) {
        *typenum = PyArray_CDOUBLE;
        return PyArray_DescrFromType(PyArray_DOUBLE);
    }
    if (PyArray_IsScalar(self, CFloat)) {
        *typenum = PyArray_CFLOAT;
        return PyArray_DescrFromType(PyArray_FLOAT);
    }
    if (PyArray_IsScalar(self, CLongDouble)) {
        *typenum = PyArray_CLONGDOUBLE;
        return PyArray_DescrFromType(PyArray_LONGDOUBLE);
    }
    return NULL;
}

static PyObject *
gentype_real_get(PyObject *self)
{
    PyArray_Descr *typecode;
    PyObject *ret;
    int typenum;

    if (PyArray_IsScalar(self, ComplexFloating)) {
        void *ptr;
        typecode = _realdescr_fromcomplexscalar(self, &typenum);
        ptr = scalar_value(self, NULL);
        ret = PyArray_Scalar(ptr, typecode, NULL);
        Py_DECREF(typecode);
        return ret;
    }
    else if (PyArray_IsScalar(self, Object)) {
        PyObject *obj = ((PyObjectScalarObject *)self)->obval;
        ret = PyObject_GetAttrString(obj, "real");
        if (ret != NULL) {
            return ret;
        }
        PyErr_Clear();
    }
    Py_INCREF(self);
    return (PyObject *)self;
}

static PyObject *
gentype_imag_get(PyObject *self)
{
    PyArray_Descr *typecode=NULL;
    PyObject *ret;
    int typenum;

    if (PyArray_IsScalar(self, ComplexFloating)) {
        char *ptr;
        typecode = _realdescr_fromcomplexscalar(self, &typenum);
        ptr = (char *)scalar_value(self, NULL);
        ret = PyArray_Scalar(ptr + typecode->elsize, typecode, NULL);
    }
    else if (PyArray_IsScalar(self, Object)) {
        PyObject *obj = ((PyObjectScalarObject *)self)->obval;
        PyArray_Descr *newtype;
        ret = PyObject_GetAttrString(obj, "imag");
        if (ret == NULL) {
            PyErr_Clear();
            obj = PyInt_FromLong(0);
            newtype = PyArray_DescrFromType(PyArray_OBJECT);
            ret = PyArray_Scalar((char *)&obj, newtype, NULL);
            Py_DECREF(newtype);
            Py_DECREF(obj);
        }
    }
    else {
        char *temp;
        int elsize;
        typecode = PyArray_DescrFromScalar(self);
        elsize = typecode->elsize;
        temp = PyDataMem_NEW(elsize);
        memset(temp, '\0', elsize);
        ret = PyArray_Scalar(temp, typecode, NULL);
        PyDataMem_FREE(temp);
    }

    Py_XDECREF(typecode);
    return ret;
}

static PyObject *
gentype_flat_get(PyObject *self)
{
    PyObject *ret, *arr;

    arr = PyArray_FromScalar(self, NULL);
    if (arr == NULL) {
        return NULL;
    }
    ret = PyArray_IterNew(arr);
    Py_DECREF(arr);
    return ret;
}


static PyObject *
gentype_transpose_get(PyObject *self)
{
    Py_INCREF(self);
    return self;
}


static PyGetSetDef gentype_getsets[] = {
    {"ndim",
        (getter)gentype_ndim_get,
        (setter) 0,
        "number of array dimensions",
        NULL},
    {"flags",
        (getter)gentype_flags_get,
        (setter)0,
        "integer value of flags",
        NULL},
    {"shape",
        (getter)gentype_shape_get,
        (setter)0,
        "tuple of array dimensions",
        NULL},
    {"strides",
        (getter)gentype_shape_get,
        (setter) 0,
        "tuple of bytes steps in each dimension",
        NULL},
    {"data",
        (getter)gentype_data_get,
        (setter) 0,
        "pointer to start of data",
        NULL},
    {"itemsize",
        (getter)gentype_itemsize_get,
        (setter)0,
        "length of one element in bytes",
        NULL},
    {"size",
        (getter)gentype_size_get,
        (setter)0,
        "number of elements in the gentype",
        NULL},
    {"nbytes",
        (getter)gentype_itemsize_get,
        (setter)0,
        "length of item in bytes",
        NULL},
    {"base",
        (getter)gentype_base_get,
        (setter)0,
        "base object",
        NULL},
    {"dtype",
        (getter)gentype_typedescr_get,
        NULL,
        "get array data-descriptor",
        NULL},
    {"real",
        (getter)gentype_real_get,
        (setter)0,
        "real part of scalar",
        NULL},
    {"imag",
        (getter)gentype_imag_get,
        (setter)0,
        "imaginary part of scalar",
        NULL},
    {"flat",
        (getter)gentype_flat_get,
        (setter)0,
        "a 1-d view of scalar",
        NULL},
    {"T",
        (getter)gentype_transpose_get,
        (setter)0,
        "transpose",
        NULL},
    {"__array_interface__",
        (getter)gentype_interface_get,
        NULL,
        "Array protocol: Python side",
        NULL},
    {"__array_struct__",
        (getter)gentype_struct_get,
        NULL,
        "Array protocol: struct",
        NULL},
    {"__array_priority__",
        (getter)gentype_priority_get,
        NULL,
        "Array priority.",
        NULL},
    {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
};


/* 0-dim array from scalar object */

static char doc_getarray[] = "sc.__array__(|type) return 0-dim array";

static PyObject *
gentype_getarray(PyObject *scalar, PyObject *args)
{
    PyArray_Descr *outcode=NULL;
    PyObject *ret;

    if (!PyArg_ParseTuple(args, "|O&", &PyArray_DescrConverter,
                &outcode)) {
        Py_XDECREF(outcode);
        return NULL;
    }
    ret = PyArray_FromScalar(scalar, outcode);
    return ret;
}

static char doc_sc_wraparray[] = "sc.__array_wrap__(obj) return scalar from array";

static PyObject *
gentype_wraparray(PyObject *NPY_UNUSED(scalar), PyObject *args)
{
    PyObject *arr;

    if (PyTuple_Size(args) < 1) {
        PyErr_SetString(PyExc_TypeError,
                "only accepts 1 argument.");
        return NULL;
    }
    arr = PyTuple_GET_ITEM(args, 0);
    if (!PyArray_Check(arr)) {
        PyErr_SetString(PyExc_TypeError,
                "can only be called with ndarray object");
        return NULL;
    }

    return PyArray_Scalar(PyArray_DATA(arr), PyArray_DESCR(arr), arr);
}


/**begin repeat
 *
 * #name = tolist, item, tostring, astype, copy, __deepcopy__, searchsorted,
 *         view, swapaxes, conj, conjugate, nonzero, flatten, ravel, fill,
 *         transpose, newbyteorder#
 */
static PyObject *
gentype_@name@(PyObject *self, PyObject *args)
{
    return gentype_generic_method(self, args, NULL, "@name@");
}
/**end repeat**/

static PyObject *
gentype_itemset(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args))
{
    PyErr_SetString(PyExc_ValueError, "array-scalars are immutable");
    return NULL;
}

static PyObject *
gentype_squeeze(PyObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, "")) {
        return NULL;
    }
    Py_INCREF(self);
    return self;
}

static Py_ssize_t
gentype_getreadbuf(PyObject *, Py_ssize_t, void **);

static PyObject *
gentype_byteswap(PyObject *self, PyObject *args)
{
    Bool inplace=FALSE;

    if (!PyArg_ParseTuple(args, "|O&", PyArray_BoolConverter, &inplace)) {
        return NULL;
    }
    if (inplace) {
        PyErr_SetString(PyExc_ValueError,
                "cannot byteswap a scalar in-place");
        return NULL;
    }
    else {
        /* get the data, copyswap it and pass it to a new Array scalar */
        char *data;
        int numbytes;
        PyArray_Descr *descr;
        PyObject *new;
        char *newmem;

        numbytes = gentype_getreadbuf(self, 0, (void **)&data);
        descr = PyArray_DescrFromScalar(self);
        newmem = _pya_malloc(descr->elsize);
        if (newmem == NULL) {
            Py_DECREF(descr);
            return PyErr_NoMemory();
        }
        else {
            memcpy(newmem, data, descr->elsize);
        }
        byte_swap_vector(newmem, 1, descr->elsize);
        new = PyArray_Scalar(newmem, descr, NULL);
        _pya_free(newmem);
        Py_DECREF(descr);
        return new;
    }
}


/**begin repeat
 *
 * #name = take, getfield, put, repeat, tofile, mean, trace, diagonal, clip,
 *         std, var, sum, cumsum, prod, cumprod, compress, sort, argsort,
 *         round, argmax, argmin, max, min, ptp, any, all, resize, reshape,
 *         choose#
 */
static PyObject *
gentype_@name@(PyObject *self, PyObject *args, PyObject *kwds)
{
    return gentype_generic_method(self, args, kwds, "@name@");
}
/**end repeat**/

static PyObject *
voidtype_getfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *ret, *newargs;

    newargs = PyTuple_GetSlice(args, 0, 2);
    if (newargs == NULL) {
        return NULL;
    }
    ret = gentype_generic_method((PyObject *)self, newargs, kwds, "getfield");
    Py_DECREF(newargs);
    if (!ret) {
        return ret;
    }
    if (PyArray_IsScalar(ret, Generic) &&   \
            (!PyArray_IsScalar(ret, Void))) {
        PyArray_Descr *new;
        void *ptr;
        if (!PyArray_ISNBO(self->descr->byteorder)) {
            new = PyArray_DescrFromScalar(ret);
            ptr = scalar_value(ret, new);
            byte_swap_vector(ptr, 1, new->elsize);
            Py_DECREF(new);
        }
    }
    return ret;
}

static PyObject *
gentype_setfield(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
{
    PyErr_SetString(PyExc_TypeError,
            "Can't set fields in a non-void array scalar.");
    return NULL;
}

static PyObject *
voidtype_setfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds)
{
    PyArray_Descr *typecode = NULL;
    int offset = 0;
    PyObject *value, *src;
    int mysize;
    char *dptr;
    static char *kwlist[] = {"value", "dtype", "offset", 0};

    if ((self->flags & WRITEABLE) != WRITEABLE) {
        PyErr_SetString(PyExc_RuntimeError, "Can't write to memory");
        return NULL;
    }
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|i", kwlist,
                &value,
                PyArray_DescrConverter,
                &typecode, &offset)) {
        Py_XDECREF(typecode);
        return NULL;
    }

    mysize = self->ob_size;

    if (offset < 0 || (offset + typecode->elsize) > mysize) {
        PyErr_Format(PyExc_ValueError,
                "Need 0 <= offset <= %d for requested type "  \
                "but received offset = %d",
                mysize-typecode->elsize, offset);
        Py_DECREF(typecode);
        return NULL;
    }

    dptr = self->obval + offset;

    if (typecode->type_num == PyArray_OBJECT) {
        PyObject **temp;
        Py_INCREF(value);
        temp = (PyObject **)dptr;
        Py_XDECREF(*temp);
        memcpy(temp, &value, sizeof(PyObject *));
        Py_DECREF(typecode);
    }
    else {
        /* Copy data from value to correct place in dptr */
        src = PyArray_FromAny(value, typecode, 0, 0, CARRAY, NULL);
        if (src == NULL) {
            return NULL;
        }
        typecode->f->copyswap(dptr, PyArray_DATA(src),
                !PyArray_ISNBO(self->descr->byteorder),
                src);
        Py_DECREF(src);
    }
    Py_INCREF(Py_None);
    return Py_None;
}


static PyObject *
gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args))
{
    PyObject *ret = NULL, *obj = NULL, *mod = NULL;
    const char *buffer;
    Py_ssize_t buflen;

    /* Return a tuple of (callable object, arguments) */
    ret = PyTuple_New(2);
    if (ret == NULL) {
        return NULL;
    }
    if (PyObject_AsReadBuffer(self, (const void **)&buffer, &buflen)<0) {
        Py_DECREF(ret);
        return NULL;
    }
    mod = PyImport_ImportModule("numpy.core.multiarray");
    if (mod == NULL) {
        return NULL;
    }
    obj = PyObject_GetAttrString(mod, "scalar");
    Py_DECREF(mod);
    if (obj == NULL) {
        return NULL;
    }
    PyTuple_SET_ITEM(ret, 0, obj);
    obj = PyObject_GetAttrString((PyObject *)self, "dtype");
    if (PyArray_IsScalar(self, Object)) {
        mod = ((PyObjectScalarObject *)self)->obval;
        PyTuple_SET_ITEM(ret, 1, Py_BuildValue("NO", obj, mod));
    }
    else {
#ifndef Py_UNICODE_WIDE
        /*
         * We need to expand the buffer so that we always write
         * UCS4 to disk for pickle of unicode scalars.
         *
         * This could be in a unicode_reduce function, but
         * that would require re-factoring.
         */
        int alloc = 0;
        char *tmp;
        int newlen;

        if (PyArray_IsScalar(self, Unicode)) {
            tmp = _pya_malloc(buflen*2);
            if (tmp == NULL) {
                Py_DECREF(ret);
                return PyErr_NoMemory();
            }
            alloc = 1;
            newlen = PyUCS2Buffer_AsUCS4((Py_UNICODE *)buffer,
                    (PyArray_UCS4 *)tmp,
                    buflen / 2, buflen / 2);
            buflen = newlen*4;
            buffer = tmp;
        }
#endif
        mod = PyString_FromStringAndSize(buffer, buflen);
        if (mod == NULL) {
            Py_DECREF(ret);
#ifndef Py_UNICODE_WIDE
            ret = NULL;
            goto fail;
#else
            return NULL;
#endif
        }
        PyTuple_SET_ITEM(ret, 1,
                Py_BuildValue("NN", obj, mod));
#ifndef Py_UNICODE_WIDE
fail:
        if (alloc) _pya_free((char *)buffer);
#endif
    }
    return ret;
}

/* ignores everything */
static PyObject *
gentype_setstate(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args))
{
    Py_INCREF(Py_None);
    return (Py_None);
}

static PyObject *
gentype_dump(PyObject *self, PyObject *args)
{
    PyObject *file = NULL;
    int ret;

    if (!PyArg_ParseTuple(args, "O", &file)) {
        return NULL;
    }
    ret = PyArray_Dump(self, file, 2);
    if (ret < 0) {
        return NULL;
    }
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
gentype_dumps(PyObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, "")) {
        return NULL;
    }
    return PyArray_Dumps(self, 2);
}


/* setting flags cannot be done for scalars */
static PyObject *
gentype_setflags(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args),
        PyObject *NPY_UNUSED(kwds))
{
    Py_INCREF(Py_None);
    return Py_None;
}

/* need to fill in doc-strings for these methods on import -- copy from
   array docstrings
*/
static PyMethodDef gentype_methods[] = {
    {"tolist",
        (PyCFunction)gentype_tolist,   1, NULL},
    {"item",
        (PyCFunction)gentype_item, METH_VARARGS, NULL},
    {"itemset",
        (PyCFunction)gentype_itemset, METH_VARARGS, NULL},
    {"tofile", (PyCFunction)gentype_tofile,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"tostring",
        (PyCFunction)gentype_tostring, METH_VARARGS, NULL},
    {"byteswap",
        (PyCFunction)gentype_byteswap,1, NULL},
    {"astype",
        (PyCFunction)gentype_astype, 1, NULL},
    {"getfield",
        (PyCFunction)gentype_getfield,
        METH_VARARGS | METH_KEYWORDS, NULL},
    {"setfield",
        (PyCFunction)gentype_setfield,
        METH_VARARGS | METH_KEYWORDS, NULL},
    {"copy",
        (PyCFunction)gentype_copy, 1, NULL},
    {"resize", (PyCFunction)gentype_resize,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"__array__",
        (PyCFunction)gentype_getarray, 1, doc_getarray},
    {"__array_wrap__",
        (PyCFunction)gentype_wraparray, 1, doc_sc_wraparray},

    /* for the copy module */
    {"__copy__",
        (PyCFunction)gentype_copy, 1, NULL},
    {"__deepcopy__",
        (PyCFunction)gentype___deepcopy__, 1, NULL},

    {"__reduce__",
        (PyCFunction) gentype_reduce, 1, NULL},
    /* For consistency does nothing */
    {"__setstate__",
        (PyCFunction) gentype_setstate, 1, NULL},

    {"dumps",
        (PyCFunction) gentype_dumps, 1, NULL},
    {"dump",
        (PyCFunction) gentype_dump, 1, NULL},

    /* Methods for array */
    {"fill",
        (PyCFunction)gentype_fill,
        METH_VARARGS, NULL},
    {"transpose",
        (PyCFunction)gentype_transpose,
        METH_VARARGS, NULL},
    {"take",
        (PyCFunction)gentype_take,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"put",
        (PyCFunction)gentype_put,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"repeat",
        (PyCFunction)gentype_repeat,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"choose",
        (PyCFunction)gentype_choose,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"sort",
        (PyCFunction)gentype_sort,
        METH_VARARGS, NULL},
    {"argsort",
        (PyCFunction)gentype_argsort,
        METH_VARARGS, NULL},
    {"searchsorted",
        (PyCFunction)gentype_searchsorted,
        METH_VARARGS, NULL},
    {"argmax",
        (PyCFunction)gentype_argmax,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"argmin",
        (PyCFunction)gentype_argmin,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"reshape",
        (PyCFunction)gentype_reshape,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"squeeze",
        (PyCFunction)gentype_squeeze,
        METH_VARARGS, NULL},
    {"view",
        (PyCFunction)gentype_view,
        METH_VARARGS, NULL},
    {"swapaxes",
        (PyCFunction)gentype_swapaxes,
        METH_VARARGS, NULL},
    {"max",
        (PyCFunction)gentype_max,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"min",
        (PyCFunction)gentype_min,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"ptp",
        (PyCFunction)gentype_ptp,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"mean",
        (PyCFunction)gentype_mean,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"trace",
        (PyCFunction)gentype_trace,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"diagonal",
        (PyCFunction)gentype_diagonal,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"clip",
        (PyCFunction)gentype_clip,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"conj",
        (PyCFunction)gentype_conj,
        METH_VARARGS, NULL},
    {"conjugate",
        (PyCFunction)gentype_conjugate,
        METH_VARARGS, NULL},
    {"nonzero",
        (PyCFunction)gentype_nonzero,
        METH_VARARGS, NULL},
    {"std",
        (PyCFunction)gentype_std,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"var",
        (PyCFunction)gentype_var,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"sum",
        (PyCFunction)gentype_sum,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"cumsum",
        (PyCFunction)gentype_cumsum,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"prod",
        (PyCFunction)gentype_prod,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"cumprod",
        (PyCFunction)gentype_cumprod,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"all",
        (PyCFunction)gentype_all,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"any",
        (PyCFunction)gentype_any,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"compress",
        (PyCFunction)gentype_compress,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"flatten",
        (PyCFunction)gentype_flatten,
        METH_VARARGS, NULL},
    {"ravel",
        (PyCFunction)gentype_ravel,
        METH_VARARGS, NULL},
    {"round",
        (PyCFunction)gentype_round,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"setflags",
        (PyCFunction)gentype_setflags,
        METH_VARARGS|METH_KEYWORDS, NULL},
    {"newbyteorder",
        (PyCFunction)gentype_newbyteorder,
        METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL} /* sentinel */
};


static PyGetSetDef voidtype_getsets[] = {
    {"flags",
        (getter)voidtype_flags_get,
        (setter)0,
        "integer value of flags",
        NULL},
    {"dtype",
        (getter)voidtype_dtypedescr_get,
        (setter)0,
        "dtype object",
        NULL},
    {NULL, NULL, NULL, NULL, NULL}
};

static PyMethodDef voidtype_methods[] = {
    {"getfield",
        (PyCFunction)voidtype_getfield,
        METH_VARARGS | METH_KEYWORDS, NULL},
    {"setfield",
        (PyCFunction)voidtype_setfield,
        METH_VARARGS | METH_KEYWORDS, NULL},
    {NULL, NULL, 0, NULL}
};

/************* As_mapping functions for void array scalar ************/

static Py_ssize_t
voidtype_length(PyVoidScalarObject *self)
{
    if (!self->descr->names) {
        return 0;
    }
    else { /* return the number of fields */
        return (Py_ssize_t) PyTuple_GET_SIZE(self->descr->names);
    }
}

static PyObject *
voidtype_item(PyVoidScalarObject *self, Py_ssize_t n)
{
    intp m;
    PyObject *flist=NULL, *fieldinfo;

    if (!(PyDescr_HASFIELDS(self->descr))) {
        PyErr_SetString(PyExc_IndexError,
                "can't index void scalar without fields");
        return NULL;
    }
    flist = self->descr->names;
    m = PyTuple_GET_SIZE(flist);
    if (n < 0) {
        n += m;
    }
    if (n < 0 || n >= m) {
        PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n);
        return NULL;
    }
    fieldinfo = PyDict_GetItem(self->descr->fields,
            PyTuple_GET_ITEM(flist, n));
    return voidtype_getfield(self, fieldinfo, NULL);
}


/* get field by name or number */
static PyObject *
voidtype_subscript(PyVoidScalarObject *self, PyObject *ind)
{
    intp n;
    PyObject *fieldinfo;

    if (!(PyDescr_HASFIELDS(self->descr))) {
        PyErr_SetString(PyExc_IndexError,
                "can't index void scalar without fields");
        return NULL;
    }

    if (PyString_Check(ind) || PyUnicode_Check(ind)) {
        /* look up in fields */
        fieldinfo = PyDict_GetItem(self->descr->fields, ind);
        if (!fieldinfo) {
            goto fail;
        }
        return voidtype_getfield(self, fieldinfo, NULL);
    }

    /* try to convert it to a number */
    n = PyArray_PyIntAsIntp(ind);
    if (error_converting(n)) {
        goto fail;
    }
    return voidtype_item(self, (Py_ssize_t)n);

fail:
    PyErr_SetString(PyExc_IndexError, "invalid index");
    return NULL;
}

static int
voidtype_ass_item(PyVoidScalarObject *self, Py_ssize_t n, PyObject *val)
{
    intp m;
    PyObject *flist=NULL, *fieldinfo, *newtup;
    PyObject *res;

    if (!(PyDescr_HASFIELDS(self->descr))) {
        PyErr_SetString(PyExc_IndexError,
                "can't index void scalar without fields");
        return -1;
    }

    flist = self->descr->names;
    m = PyTuple_GET_SIZE(flist);
    if (n < 0) {
        n += m;
    }
    if (n < 0 || n >= m) {
        goto fail;
    }
    fieldinfo = PyDict_GetItem(self->descr->fields,
            PyTuple_GET_ITEM(flist, n));
    newtup = Py_BuildValue("(OOO)", val,
            PyTuple_GET_ITEM(fieldinfo, 0),
            PyTuple_GET_ITEM(fieldinfo, 1));
    res = voidtype_setfield(self, newtup, NULL);
    Py_DECREF(newtup);
    if (!res) {
        return -1;
    }
    Py_DECREF(res);
    return 0;

fail:
    PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n);
    return -1;
}

static int
voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val)
{
    intp n;
    char *msg = "invalid index";
    PyObject *fieldinfo, *newtup;
    PyObject *res;

    if (!PyDescr_HASFIELDS(self->descr)) {
        PyErr_SetString(PyExc_IndexError,
                "can't index void scalar without fields");
        return -1;
    }

    if (PyString_Check(ind) || PyUnicode_Check(ind)) {
        /* look up in fields */
        fieldinfo = PyDict_GetItem(self->descr->fields, ind);
        if (!fieldinfo) {
            goto fail;
        }
        newtup = Py_BuildValue("(OOO)", val,
                PyTuple_GET_ITEM(fieldinfo, 0),
                PyTuple_GET_ITEM(fieldinfo, 1));
        res = voidtype_setfield(self, newtup, NULL);
        Py_DECREF(newtup);
        if (!res) {
            return -1;
        }
        Py_DECREF(res);
        return 0;
    }

    /* try to convert it to a number */
    n = PyArray_PyIntAsIntp(ind);
    if (error_converting(n)) {
        goto fail;
    }
    return voidtype_ass_item(self, (Py_ssize_t)n, val);

fail:
    PyErr_SetString(PyExc_IndexError, msg);
    return -1;
}

static PyMappingMethods voidtype_as_mapping = {
#if PY_VERSION_HEX >= 0x02050000
    (lenfunc)voidtype_length,                    /*mp_length*/
#else
    (inquiry)voidtype_length,                    /*mp_length*/
#endif
    (binaryfunc)voidtype_subscript,              /*mp_subscript*/
    (objobjargproc)voidtype_ass_subscript,       /*mp_ass_subscript*/
};


static PySequenceMethods voidtype_as_sequence = {
#if PY_VERSION_HEX >= 0x02050000
    (lenfunc)voidtype_length,                    /*sq_length*/
    0,                                           /*sq_concat*/
    0,                                           /*sq_repeat*/
    (ssizeargfunc)voidtype_item,                 /*sq_item*/
    0,                                           /*sq_slice*/
    (ssizeobjargproc)voidtype_ass_item,          /*sq_ass_item*/
#else
        (inquiry)voidtype_length,                /*sq_length*/
    0,                                           /*sq_concat*/
    0,                                           /*sq_repeat*/
    (intargfunc)voidtype_item,                   /*sq_item*/
    0,                                           /*sq_slice*/
    (intobjargproc)voidtype_ass_item,            /*sq_ass_item*/
#endif
    0,                                           /* ssq_ass_slice */
    0,                                           /* sq_contains */
    0,                                           /* sq_inplace_concat */
    0,                                           /* sq_inplace_repeat */
};



static Py_ssize_t
gentype_getreadbuf(PyObject *self, Py_ssize_t segment, void **ptrptr)
{
    int numbytes;
    PyArray_Descr *outcode;

    if (segment != 0) {
        PyErr_SetString(PyExc_SystemError,
                "Accessing non-existent array segment");
        return -1;
    }

    outcode = PyArray_DescrFromScalar(self);
    numbytes = outcode->elsize;
    *ptrptr = (void *)scalar_value(self, outcode);

#ifndef Py_UNICODE_WIDE
    if (outcode->type_num == NPY_UNICODE) {
        numbytes >>= 1;
    }
#endif
    Py_DECREF(outcode);
    return numbytes;
}

static Py_ssize_t
gentype_getsegcount(PyObject *self, Py_ssize_t *lenp)
{
    PyArray_Descr *outcode;

    outcode = PyArray_DescrFromScalar(self);
    if (lenp) {
        *lenp = outcode->elsize;
#ifndef Py_UNICODE_WIDE
        if (outcode->type_num == NPY_UNICODE) {
            *lenp >>= 1;
        }
#endif
    }
    Py_DECREF(outcode);
    return 1;
}

static Py_ssize_t
gentype_getcharbuf(PyObject *self, Py_ssize_t segment, constchar **ptrptr)
{
    if (PyArray_IsScalar(self, String) ||
            PyArray_IsScalar(self, Unicode)) {
        return gentype_getreadbuf(self, segment, (void **)ptrptr);
    }
    else {
        PyErr_SetString(PyExc_TypeError,
                "Non-character array cannot be interpreted "\
                "as character buffer.");
        return -1;
    }
}


static PyBufferProcs gentype_as_buffer = {
    gentype_getreadbuf,                          /* bf_getreadbuffer*/
    NULL,                                        /* bf_getwritebuffer*/
    gentype_getsegcount,                         /* bf_getsegcount*/
    gentype_getcharbuf,                          /* bf_getcharbuffer*/
};


#define BASEFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES
#define LEAFFLAGS  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES

static PyTypeObject PyGenericArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.generic",                             /* tp_name*/
    sizeof(PyObject),                            /* tp_basicsize*/
    0,                                           /* tp_itemsize */
    /* methods */
    0,                                           /* tp_dealloc */
    0,                                           /* tp_print */
    0,                                           /* tp_getattr */
    0,                                           /* tp_setattr */
    0,                                           /* tp_compare */
    0,                                           /* tp_repr */
    0,                                           /* tp_as_number */
    0,                                           /* tp_as_sequence */
    0,                                           /* tp_as_mapping */
    0,                                           /* tp_hash */
    0,                                           /* tp_call */
    0,                                           /* tp_str */
    0,                                           /* tp_getattro */
    0,                                           /* tp_setattro */
    0,                                           /* tp_as_buffer */
    0,                                           /* tp_flags */
    0,                                           /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */

#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};

static void
void_dealloc(PyVoidScalarObject *v)
{
    if (v->flags & OWNDATA) {
        PyDataMem_FREE(v->obval);
    }
    Py_XDECREF(v->descr);
    Py_XDECREF(v->base);
    v->ob_type->tp_free(v);
}

static void
object_arrtype_dealloc(PyObject *v)
{
    Py_XDECREF(((PyObjectScalarObject *)v)->obval);
    v->ob_type->tp_free(v);
}

/*
 * string and unicode inherit from Python Type first and so GET_ITEM
 * is different to get to the Python Type.
 *
 * ok is a work-around for a bug in complex_new that doesn't allocate
 *  memory from the sub-types memory allocator.
 */

#define _WORK(num)  \
    if (type->tp_bases && (PyTuple_GET_SIZE(type->tp_bases)==2)) { \
        PyTypeObject *sup; \
        /* We are inheriting from a Python type as well so \
           give it first dibs on conversion */ \
        sup = (PyTypeObject *)PyTuple_GET_ITEM(type->tp_bases, num); \
        robj = sup->tp_new(type, args, kwds); \
        if (robj != NULL) goto finish;              \
        if (PyTuple_GET_SIZE(args)!=1) return NULL; \
        PyErr_Clear(); \
        /* now do default conversion */ \
    }

#define _WORK1 _WORK(1)
#define _WORKz _WORK(0)
#define _WORK0

/**begin repeat
 * #name = byte, short, int, long, longlong, ubyte, ushort, uint, ulong,
 *         ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble,
 *         string, unicode, object#
 * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG,
 *         ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE,
 *         STRING, UNICODE, OBJECT#
 * #work = 0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,z,z,0#
 * #default = 0*16,1*2,2#
 */

#define _NPY_UNUSED2_1
#define _NPY_UNUSED2_z
#define _NPY_UNUSED2_0 NPY_UNUSED
#define _NPY_UNUSED1_0
#define _NPY_UNUSED1_1
#define _NPY_UNUSED1_2 NPY_UNUSED

static PyObject *
@name@_arrtype_new(PyTypeObject *_NPY_UNUSED1_@default@(type), PyObject *args, PyObject *_NPY_UNUSED2_@work@(kwds))
{
    PyObject *obj = NULL;
    PyObject *robj;
    PyObject *arr;
    PyArray_Descr *typecode = NULL;
#if !(@default@ == 2)
    int itemsize;
    void *dest, *src;
#endif

    /*
     * allow base-class (if any) to do conversion
     * If successful, this will jump to finish:
     */
    _WORK@work@

    if (!PyArg_ParseTuple(args, "|O", &obj)) {
        return NULL;
    }
    typecode = PyArray_DescrFromType(PyArray_@TYPE@);
    /*
     * typecode is new reference and stolen by
     * PyArray_FromAny but not PyArray_Scalar
     */
    if (obj == NULL) {
#if @default@ == 0
        char *mem = malloc(sizeof(@name@));

        memset(mem, 0, sizeof(@name@));
        robj = PyArray_Scalar(mem, typecode, NULL);
        free(mem);
#elif @default@ == 1
        robj = PyArray_Scalar(NULL, typecode, NULL);
#elif @default@ == 2
        Py_INCREF(Py_None);
        robj = Py_None;
#endif
        Py_DECREF(typecode);
        goto finish;
    }

    /*
     * It is expected at this point that robj is a PyArrayScalar
     * (even for Object Data Type)
     */
    arr = PyArray_FromAny(obj, typecode, 0, 0, FORCECAST, NULL);
    if ((arr == NULL) || (PyArray_NDIM(arr) > 0)) {
        return arr;
    }
    /* 0-d array */
    robj = PyArray_ToScalar(PyArray_DATA(arr), (NPY_AO *)arr);
    Py_DECREF(arr);

finish:
    /*
     * In OBJECT case, robj is no longer a
     * PyArrayScalar at this point but the
     * remaining code assumes it is
     */
#if @default@ == 2
    return robj;
#else
    /* Normal return */
    if ((robj == NULL) || (robj->ob_type == type)) {
        return robj;
    }

    /*
     * This return path occurs when the requested type is not created
     * but another scalar object is created instead (i.e. when
     * the base-class does the conversion in _WORK macro)
     */

    /* Need to allocate new type and copy data-area over */
    if (type->tp_itemsize) {
        itemsize = PyString_GET_SIZE(robj);
    }
    else {
        itemsize = 0;
    }
    obj = type->tp_alloc(type, itemsize);
    if (obj == NULL) {
        Py_DECREF(robj);
        return NULL;
    }
    /* typecode will be NULL */
    typecode = PyArray_DescrFromType(PyArray_@TYPE@);
    dest = scalar_value(obj, typecode);
    src = scalar_value(robj, typecode);
    Py_DECREF(typecode);
#if @default@ == 0
    *((npy_@name@ *)dest) = *((npy_@name@ *)src);
#elif @default@ == 1 /* unicode and strings */
    if (itemsize == 0) { /* unicode */
        itemsize = ((PyUnicodeObject *)robj)->length * sizeof(Py_UNICODE);
    }
    memcpy(dest, src, itemsize);
    /* @default@ == 2 won't get here */
#endif
    Py_DECREF(robj);
    return obj;
#endif
}
/**end repeat**/

#undef _WORK1
#undef _WORKz
#undef _WORK0
#undef _WORK

/* bool->tp_new only returns Py_True or Py_False */
static PyObject *
bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *NPY_UNUSED(kwds))
{
    PyObject *obj = NULL;
    PyObject *arr;

    if (!PyArg_ParseTuple(args, "|O", &obj)) {
        return NULL;
    }
    if (obj == NULL) {
        PyArrayScalar_RETURN_FALSE;
    }
    if (obj == Py_False) {
        PyArrayScalar_RETURN_FALSE;
    }
    if (obj == Py_True) {
        PyArrayScalar_RETURN_TRUE;
    }
    arr = PyArray_FROM_OTF(obj, PyArray_BOOL, FORCECAST);
    if (arr && 0 == PyArray_NDIM(arr)) {
        Bool val = *((Bool *)PyArray_DATA(arr));
        Py_DECREF(arr);
        PyArrayScalar_RETURN_BOOL_FROM_LONG(val);
    }
    return PyArray_Return((PyArrayObject *)arr);
}

static PyObject *
bool_arrtype_and(PyObject *a, PyObject *b)
{
    if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) {
        PyArrayScalar_RETURN_BOOL_FROM_LONG
            ((a == PyArrayScalar_True)&(b == PyArrayScalar_True));
    }
    return PyGenericArrType_Type.tp_as_number->nb_and(a, b);
}

static PyObject *
bool_arrtype_or(PyObject *a, PyObject *b)
{
    if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) {
        PyArrayScalar_RETURN_BOOL_FROM_LONG
            ((a == PyArrayScalar_True)|(b == PyArrayScalar_True));
    }
    return PyGenericArrType_Type.tp_as_number->nb_or(a, b);
}

static PyObject *
bool_arrtype_xor(PyObject *a, PyObject *b)
{
    if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) {
        PyArrayScalar_RETURN_BOOL_FROM_LONG
            ((a == PyArrayScalar_True)^(b == PyArrayScalar_True));
    }
    return PyGenericArrType_Type.tp_as_number->nb_xor(a, b);
}

static int
bool_arrtype_nonzero(PyObject *a)
{
    return a == PyArrayScalar_True;
}

#if PY_VERSION_HEX >= 0x02050000
/**begin repeat
 * #name = byte, short, int, long, ubyte, ushort, longlong, uint, ulong,
 *         ulonglong#
 * #Name = Byte, Short, Int, Long, UByte, UShort, LongLong, UInt, ULong,
 *         ULongLong#
 * #type = PyInt_FromLong*6, PyLong_FromLongLong*1, PyLong_FromUnsignedLong*2,
 *         PyLong_FromUnsignedLongLong#
 */
static PyNumberMethods @name@_arrtype_as_number;
static PyObject *
@name@_index(PyObject *self)
{
    return @type@(PyArrayScalar_VAL(self, @Name@));
}
/**end repeat**/

static PyObject *
bool_index(PyObject *a)
{
    return PyInt_FromLong(PyArrayScalar_VAL(a, Bool));
}
#endif

/* Arithmetic methods -- only so we can override &, |, ^. */
static PyNumberMethods bool_arrtype_as_number = {
    0,                                           /* nb_add */
    0,                                           /* nb_subtract */
    0,                                           /* nb_multiply */
    0,                                           /* nb_divide */
    0,                                           /* nb_remainder */
    0,                                           /* nb_divmod */
    0,                                           /* nb_power */
    0,                                           /* nb_negative */
    0,                                           /* nb_positive */
    0,                                           /* nb_absolute */
    (inquiry)bool_arrtype_nonzero,               /* nb_nonzero */
    0,                                           /* nb_invert */
    0,                                           /* nb_lshift */
    0,                                           /* nb_rshift */
    (binaryfunc)bool_arrtype_and,                /* nb_and */
    (binaryfunc)bool_arrtype_xor,                /* nb_xor */
    (binaryfunc)bool_arrtype_or,                 /* nb_or */
    0,                                           /* nb_coerce */
    0,                                           /* nb_int */
    0,                                           /* nb_long */
    0,                                           /* nb_float */
    0,                                           /* nb_oct */
    0,                                           /* nb_hex */
    /* Added in release 2.0 */
    0,                                           /* nb_inplace_add */
    0,                                           /* nb_inplace_subtract */
    0,                                           /* nb_inplace_multiply */
    0,                                           /* nb_inplace_divide */
    0,                                           /* nb_inplace_remainder */
    0,                                           /* nb_inplace_power */
    0,                                           /* nb_inplace_lshift */
    0,                                           /* nb_inplace_rshift */
    0,                                           /* nb_inplace_and */
    0,                                           /* nb_inplace_xor */
    0,                                           /* nb_inplace_or */
    /* Added in release 2.2 */
    /* The following require the Py_TPFLAGS_HAVE_CLASS flag */
    0,                                           /* nb_floor_divide */
    0,                                           /* nb_true_divide */
    0,                                           /* nb_inplace_floor_divide */
    0,                                           /* nb_inplace_true_divide */
    /* Added in release 2.5 */
#if PY_VERSION_HEX >= 0x02050000
    0,                                           /* nb_index */
#endif
};

static PyObject *
void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *NPY_UNUSED(kwds))
{
    PyObject *obj, *arr;
    ulonglong memu = 1;
    PyObject *new = NULL;
    char *destptr;

    if (!PyArg_ParseTuple(args, "O", &obj)) {
        return NULL;
    }
    /*
     * For a VOID scalar first see if obj is an integer or long
     * and create new memory of that size (filled with 0) for the scalar
     */
    if (PyLong_Check(obj) || PyInt_Check(obj) ||
            PyArray_IsScalar(obj, Integer) ||
            (PyArray_Check(obj) && PyArray_NDIM(obj)==0 &&
             PyArray_ISINTEGER(obj))) {
        new = obj->ob_type->tp_as_number->nb_long(obj);
    }
    if (new && PyLong_Check(new)) {
        PyObject *ret;
        memu = PyLong_AsUnsignedLongLong(new);
        Py_DECREF(new);
        if (PyErr_Occurred() || (memu > MAX_INT)) {
            PyErr_Clear();
            PyErr_Format(PyExc_OverflowError,
                    "size must be smaller than %d",
                    (int) MAX_INT);
            return NULL;
        }
        destptr = PyDataMem_NEW((int) memu);
        if (destptr == NULL) {
            return PyErr_NoMemory();
        }
        ret = type->tp_alloc(type, 0);
        if (ret == NULL) {
            PyDataMem_FREE(destptr);
            return PyErr_NoMemory();
        }
        ((PyVoidScalarObject *)ret)->obval = destptr;
        ((PyVoidScalarObject *)ret)->ob_size = (int) memu;
        ((PyVoidScalarObject *)ret)->descr =
            PyArray_DescrNewFromType(PyArray_VOID);
        ((PyVoidScalarObject *)ret)->descr->elsize = (int) memu;
        ((PyVoidScalarObject *)ret)->flags = BEHAVED | OWNDATA;
        ((PyVoidScalarObject *)ret)->base = NULL;
        memset(destptr, '\0', (size_t) memu);
        return ret;
    }

    arr = PyArray_FROM_OTF(obj, PyArray_VOID, FORCECAST);
    return PyArray_Return((PyArrayObject *)arr);
}


/****************  Define Hash functions ********************/

/**begin repeat
 * #lname = bool,ubyte,ushort#
 * #name = Bool,UByte, UShort#
 */
static long
@lname@_arrtype_hash(PyObject *obj)
{
    return (long)(((Py@name@ScalarObject *)obj)->obval);
}
/**end repeat**/

/**begin repeat
 * #lname=byte,short,uint,ulong#
 * #name=Byte,Short,UInt,ULong#
 */
static long
@lname@_arrtype_hash(PyObject *obj)
{
    long x = (long)(((Py@name@ScalarObject *)obj)->obval);
    if (x == -1) {
        x = -2;
    }
    return x;
}
/**end repeat**/

#if SIZEOF_INT != SIZEOF_LONG
static long
int_arrtype_hash(PyObject *obj)
{
    long x = (long)(((PyIntScalarObject *)obj)->obval);
    if (x == -1) {
        x = -2;
    }
    return x;
}
#endif

/**begin repeat
 * #char = ,u#
 * #Char = ,U#
 * #ext = && (x >= LONG_MIN),#
 */
#if SIZEOF_LONG != SIZEOF_LONGLONG
/* we assume SIZEOF_LONGLONG=2*SIZEOF_LONG */
static long
@char@longlong_arrtype_hash(PyObject *obj)
{
    long y;
    @char@longlong x = (((Py@Char@LongLongScalarObject *)obj)->obval);

    if ((x <= LONG_MAX)@ext@) {
        y = (long) x;
    }
    else {
        union Mask {
            long hashvals[2];
            @char@longlong v;
        } both;

        both.v = x;
        y = both.hashvals[0] + (1000003)*both.hashvals[1];
    }
    if (y == -1) {
        y = -2;
    }
    return y;
}
#endif
/**end repeat**/

#if SIZEOF_LONG==SIZEOF_LONGLONG
static long
ulonglong_arrtype_hash(PyObject *obj)
{
    long x = (long)(((PyULongLongScalarObject *)obj)->obval);
    if (x == -1) {
        x = -2;
    }
    return x;
}
#endif



/* Wrong thing to do for longdouble, but....*/

/**begin repeat
 * #lname = float, longdouble#
 * #name = Float, LongDouble#
 */
static long
@lname@_arrtype_hash(PyObject *obj)
{
    return _Py_HashDouble((double) ((Py@name@ScalarObject *)obj)->obval);
}

/* borrowed from complex_hash */
static long
c@lname@_arrtype_hash(PyObject *obj)
{
    long hashreal, hashimag, combined;
    hashreal = _Py_HashDouble((double)
            (((PyC@name@ScalarObject *)obj)->obval).real);

    if (hashreal == -1) {
        return -1;
    }
    hashimag = _Py_HashDouble((double)
            (((PyC@name@ScalarObject *)obj)->obval).imag);
    if (hashimag == -1) {
        return -1;
    }
    combined = hashreal + 1000003 * hashimag;
    if (combined == -1) {
        combined = -2;
    }
    return combined;
}
/**end repeat**/

static long
object_arrtype_hash(PyObject *obj)
{
    return PyObject_Hash(((PyObjectScalarObject *)obj)->obval);
}

/* just hash the pointer */
static long
void_arrtype_hash(PyObject *obj)
{
    return _Py_HashPointer((void *)(((PyVoidScalarObject *)obj)->obval));
}

/*object arrtype getattro and setattro */
static PyObject *
object_arrtype_getattro(PyObjectScalarObject *obj, PyObject *attr) {
    PyObject *res;

    /* first look in object and then hand off to generic type */

    res = PyObject_GenericGetAttr(obj->obval, attr);
    if (res) {
        return res;
    }
    PyErr_Clear();
    return  PyObject_GenericGetAttr((PyObject *)obj, attr);
}

static int
object_arrtype_setattro(PyObjectScalarObject *obj, PyObject *attr, PyObject *val) {
    int res;
    /* first look in object and then hand off to generic type */

    res = PyObject_GenericSetAttr(obj->obval, attr, val);
    if (res >= 0) {
        return res;
    }
    PyErr_Clear();
    return PyObject_GenericSetAttr((PyObject *)obj, attr, val);
}

static PyObject *
object_arrtype_concat(PyObjectScalarObject *self, PyObject *other)
{
    return PySequence_Concat(self->obval, other);
}

static Py_ssize_t
object_arrtype_length(PyObjectScalarObject *self)
{
    return PyObject_Length(self->obval);
}

static PyObject *
object_arrtype_repeat(PyObjectScalarObject *self, Py_ssize_t count)
{
    return PySequence_Repeat(self->obval, count);
}

static PyObject *
object_arrtype_subscript(PyObjectScalarObject *self, PyObject *key)
{
    return PyObject_GetItem(self->obval, key);
}

static int
object_arrtype_ass_subscript(PyObjectScalarObject *self, PyObject *key,
                             PyObject *value)
{
    return PyObject_SetItem(self->obval, key, value);
}

static int
object_arrtype_contains(PyObjectScalarObject *self, PyObject *ob)
{
    return PySequence_Contains(self->obval, ob);
}

static PyObject *
object_arrtype_inplace_concat(PyObjectScalarObject *self, PyObject *o)
{
    return PySequence_InPlaceConcat(self->obval, o);
}

static PyObject *
object_arrtype_inplace_repeat(PyObjectScalarObject *self, Py_ssize_t count)
{
    return PySequence_InPlaceRepeat(self->obval, count);
}

static PySequenceMethods object_arrtype_as_sequence = {
#if PY_VERSION_HEX >= 0x02050000
    (lenfunc)object_arrtype_length,              /*sq_length*/
    (binaryfunc)object_arrtype_concat,           /*sq_concat*/
    (ssizeargfunc)object_arrtype_repeat,         /*sq_repeat*/
    0,                                           /*sq_item*/
    0,                                           /*sq_slice*/
    0,                                           /* sq_ass_item */
    0,                                           /* sq_ass_slice */
    (objobjproc)object_arrtype_contains,         /* sq_contains */
    (binaryfunc)object_arrtype_inplace_concat,   /* sq_inplace_concat */
    (ssizeargfunc)object_arrtype_inplace_repeat, /* sq_inplace_repeat */
#else
    (inquiry)object_arrtype_length,              /*sq_length*/
    (binaryfunc)object_arrtype_concat,           /*sq_concat*/
    (intargfunc)object_arrtype_repeat,           /*sq_repeat*/
    0,                                           /*sq_item*/
    0,                                           /*sq_slice*/
    0,                                           /* sq_ass_item */
    0,                                           /* sq_ass_slice */
    (objobjproc)object_arrtype_contains,         /* sq_contains */
    (binaryfunc)object_arrtype_inplace_concat,   /* sq_inplace_concat */
    (intargfunc)object_arrtype_inplace_repeat,   /* sq_inplace_repeat */
#endif
};

static PyMappingMethods object_arrtype_as_mapping = {
#if PY_VERSION_HEX >= 0x02050000
    (lenfunc)object_arrtype_length,
    (binaryfunc)object_arrtype_subscript,
    (objobjargproc)object_arrtype_ass_subscript,
#else
    (inquiry)object_arrtype_length,
    (binaryfunc)object_arrtype_subscript,
    (objobjargproc)object_arrtype_ass_subscript,
#endif
};

static Py_ssize_t
object_arrtype_getsegcount(PyObjectScalarObject *self, Py_ssize_t *lenp)
{
    Py_ssize_t newlen;
    int cnt;
    PyBufferProcs *pb = self->obval->ob_type->tp_as_buffer;

    if (pb == NULL ||
            pb->bf_getsegcount == NULL ||
            (cnt = (*pb->bf_getsegcount)(self->obval, &newlen)) != 1) {
        return 0;
    }
    if (lenp) {
        *lenp = newlen;
    }
    return cnt;
}

static Py_ssize_t
object_arrtype_getreadbuf(PyObjectScalarObject *self, Py_ssize_t segment, void **ptrptr)
{
    PyBufferProcs *pb = self->obval->ob_type->tp_as_buffer;

    if (pb == NULL ||
            pb->bf_getreadbuffer == NULL ||
            pb->bf_getsegcount == NULL) {
        PyErr_SetString(PyExc_TypeError,
                "expected a readable buffer object");
        return -1;
    }
    return (*pb->bf_getreadbuffer)(self->obval, segment, ptrptr);
}

static Py_ssize_t
object_arrtype_getwritebuf(PyObjectScalarObject *self, Py_ssize_t segment, void **ptrptr)
{
    PyBufferProcs *pb = self->obval->ob_type->tp_as_buffer;

    if (pb == NULL ||
            pb->bf_getwritebuffer == NULL ||
            pb->bf_getsegcount == NULL) {
        PyErr_SetString(PyExc_TypeError,
                "expected a writeable buffer object");
        return -1;
    }
    return (*pb->bf_getwritebuffer)(self->obval, segment, ptrptr);
}

static Py_ssize_t
object_arrtype_getcharbuf(PyObjectScalarObject *self, Py_ssize_t segment,
                          constchar **ptrptr)
{
    PyBufferProcs *pb = self->obval->ob_type->tp_as_buffer;

    if (pb == NULL ||
            pb->bf_getcharbuffer == NULL ||
            pb->bf_getsegcount == NULL) {
        PyErr_SetString(PyExc_TypeError,
                "expected a character buffer object");
        return -1;
    }
    return (*pb->bf_getcharbuffer)(self->obval, segment, ptrptr);
}

static PyBufferProcs object_arrtype_as_buffer = {
#if PY_VERSION_HEX >= 0x02050000
    (readbufferproc)object_arrtype_getreadbuf,
    (writebufferproc)object_arrtype_getwritebuf,
    (segcountproc)object_arrtype_getsegcount,
    (charbufferproc)object_arrtype_getcharbuf,
#else
    (getreadbufferproc)object_arrtype_getreadbuf,
    (getwritebufferproc)object_arrtype_getwritebuf,
    (getsegcountproc)object_arrtype_getsegcount,
    (getcharbufferproc)object_arrtype_getcharbuf,
#endif
};

static PyObject *
object_arrtype_call(PyObjectScalarObject *obj, PyObject *args, PyObject *kwds)
{
    return PyObject_Call(obj->obval, args, kwds);
}

static PyTypeObject PyObjectArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.object_",                             /* tp_name*/
    sizeof(PyObjectScalarObject),                /* tp_basicsize*/
    0,                                           /* tp_itemsize */
    (destructor)object_arrtype_dealloc,          /* tp_dealloc */
    0,                                           /* tp_print */
    0,                                           /* tp_getattr */
    0,                                           /* tp_setattr */
    0,                                           /* tp_compare */
    0,                                           /* tp_repr */
    0,                                           /* tp_as_number */
    &object_arrtype_as_sequence,                 /* tp_as_sequence */
    &object_arrtype_as_mapping,                  /* tp_as_mapping */
    0,                                           /* tp_hash */
    (ternaryfunc)object_arrtype_call,            /* tp_call */
    0,                                           /* tp_str */
    (getattrofunc)object_arrtype_getattro,       /* tp_getattro */
    (setattrofunc)object_arrtype_setattro,       /* tp_setattro */
    &object_arrtype_as_buffer,                   /* tp_as_buffer */
    0,                                           /* tp_flags */
    0,                                           /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */
#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};


static PyObject *
add_new_axes_0d(PyArrayObject *,  int);

static int
count_new_axes_0d(PyObject *);

static PyObject *
gen_arrtype_subscript(PyObject *self, PyObject *key)
{
    /*
     * Only [...], [...,<???>], [<???>, ...],
     * is allowed for indexing a scalar
     *
     * These return a new N-d array with a copy of
     * the data where N is the number of None's in <???>.
     */
    PyObject *res, *ret;
    int N;

    if (key == Py_Ellipsis || key == Py_None ||
            PyTuple_Check(key)) {
        res = PyArray_FromScalar(self, NULL);
    }
    else {
        PyErr_SetString(PyExc_IndexError,
                "invalid index to scalar variable.");
        return NULL;
    }
    if (key == Py_Ellipsis) {
        return res;
    }
    if (key == Py_None) {
        ret = add_new_axes_0d((PyArrayObject *)res, 1);
        Py_DECREF(res);
        return ret;
    }
    /* Must be a Tuple */
    N = count_new_axes_0d(key);
    if (N < 0) {
        return NULL;
    }
    ret = add_new_axes_0d((PyArrayObject *)res, N);
    Py_DECREF(res);
    return ret;
}


/**begin repeat
 * #name = bool, string, unicode, void#
 * #NAME = Bool, String, Unicode, Void#
 * #ex = _,_,_,#
 */
static PyTypeObject Py@NAME@ArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.@name@@ex@",                          /* tp_name*/
    sizeof(Py@NAME@ScalarObject),                /* tp_basicsize*/
    0,                                           /* tp_itemsize */
    0,                                           /* tp_dealloc */
    0,                                           /* tp_print */
    0,                                           /* tp_getattr */
    0,                                           /* tp_setattr */
    0,                                           /* tp_compare */
    0,                                           /* tp_repr */
    0,                                           /* tp_as_number */
    0,                                           /* tp_as_sequence */
    0,                                           /* tp_as_mapping */
    0,                                           /* tp_hash */
    0,                                           /* tp_call */
    0,                                           /* tp_str */
    0,                                           /* tp_getattro */
    0,                                           /* tp_setattro */
    0,                                           /* tp_as_buffer */
    0,                                           /* tp_flags */
    0,                                           /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */
#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};
/**end repeat**/

/**begin repeat
 * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong,
 *         ULongLong, Float, Double, LongDouble#
 * #name = int*5, uint*5, float*3#
 * #CNAME = (CHAR, SHORT, INT, LONG, LONGLONG)*2, FLOAT, DOUBLE, LONGDOUBLE#
 */
#if BITSOF_@CNAME@ == 8
#define _THIS_SIZE "8"
#elif BITSOF_@CNAME@ == 16
#define _THIS_SIZE "16"
#elif BITSOF_@CNAME@ == 32
#define _THIS_SIZE "32"
#elif BITSOF_@CNAME@ == 64
#define _THIS_SIZE "64"
#elif BITSOF_@CNAME@ == 80
#define _THIS_SIZE "80"
#elif BITSOF_@CNAME@ == 96
#define _THIS_SIZE "96"
#elif BITSOF_@CNAME@ == 128
#define _THIS_SIZE "128"
#elif BITSOF_@CNAME@ == 256
#define _THIS_SIZE "256"
#endif
static PyTypeObject Py@NAME@ArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.@name@" _THIS_SIZE,                   /* tp_name*/
    sizeof(Py@NAME@ScalarObject),                /* tp_basicsize*/
    0,                                           /* tp_itemsize */
    0,                                           /* tp_dealloc */
    0,                                           /* tp_print */
    0,                                           /* tp_getattr */
    0,                                           /* tp_setattr */
    0,                                           /* tp_compare */
    0,                                           /* tp_repr */
    0,                                           /* tp_as_number */
    0,                                           /* tp_as_sequence */
    0,                                           /* tp_as_mapping */
    0,                                           /* tp_hash */
    0,                                           /* tp_call */
    0,                                           /* tp_str */
    0,                                           /* tp_getattro */
    0,                                           /* tp_setattro */
    0,                                           /* tp_as_buffer */
    0,                                           /* tp_flags */
    0,                                           /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */
#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};

#undef _THIS_SIZE
/**end repeat**/


static PyMappingMethods gentype_as_mapping = {
    NULL,
    (binaryfunc)gen_arrtype_subscript,
    NULL
};


/**begin repeat
 * #NAME = CFloat, CDouble, CLongDouble#
 * #name = complex*3#
 * #CNAME = FLOAT, DOUBLE, LONGDOUBLE#
 */
#if BITSOF_@CNAME@ == 16
#define _THIS_SIZE2 "16"
#define _THIS_SIZE1 "32"
#elif BITSOF_@CNAME@ == 32
#define _THIS_SIZE2 "32"
#define _THIS_SIZE1 "64"
#elif BITSOF_@CNAME@ == 64
#define _THIS_SIZE2 "64"
#define _THIS_SIZE1 "128"
#elif BITSOF_@CNAME@ == 80
#define _THIS_SIZE2 "80"
#define _THIS_SIZE1 "160"
#elif BITSOF_@CNAME@ == 96
#define _THIS_SIZE2 "96"
#define _THIS_SIZE1 "192"
#elif BITSOF_@CNAME@ == 128
#define _THIS_SIZE2 "128"
#define _THIS_SIZE1 "256"
#elif BITSOF_@CNAME@ == 256
#define _THIS_SIZE2 "256"
#define _THIS_SIZE1 "512"
#endif

#define _THIS_DOC "Composed of two " _THIS_SIZE2 " bit floats"

    static PyTypeObject Py@NAME@ArrType_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                                           /* ob_size*/
    "numpy.@name@" _THIS_SIZE1,                  /* tp_name*/
    sizeof(Py@NAME@ScalarObject),                /* tp_basicsize*/
    0,                                           /* tp_itemsize*/
    0,                                           /* tp_dealloc*/
    0,                                           /* tp_print*/
    0,                                           /* tp_getattr*/
    0,                                           /* tp_setattr*/
    0,                                           /* tp_compare*/
    0,                                           /* tp_repr*/
    0,                                           /* tp_as_number*/
    0,                                           /* tp_as_sequence*/
    0,                                           /* tp_as_mapping*/
    0,                                           /* tp_hash */
    0,                                           /* tp_call*/
    0,                                           /* tp_str*/
    0,                                           /* tp_getattro*/
    0,                                           /* tp_setattro*/
    0,                                           /* tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
    _THIS_DOC,                                   /* tp_doc */
    0,                                           /* tp_traverse */
    0,                                           /* tp_clear */
    0,                                           /* tp_richcompare */
    0,                                           /* tp_weaklistoffset */
    0,                                           /* tp_iter */
    0,                                           /* tp_iternext */
    0,                                           /* tp_methods */
    0,                                           /* tp_members */
    0,                                           /* tp_getset */
    0,                                           /* tp_base */
    0,                                           /* tp_dict */
    0,                                           /* tp_descr_get */
    0,                                           /* tp_descr_set */
    0,                                           /* tp_dictoffset */
    0,                                           /* tp_init */
    0,                                           /* tp_alloc */
    0,                                           /* tp_new */
    0,                                           /* tp_free */
    0,                                           /* tp_is_gc */
    0,                                           /* tp_bases */
    0,                                           /* tp_mro */
    0,                                           /* tp_cache */
    0,                                           /* tp_subclasses */
    0,                                           /* tp_weaklist */
    0,                                           /* tp_del */
#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    0,                                           /* tp_allocs */
    0,                                           /* tp_frees */
    0,                                           /* tp_maxalloc */
    0,                                           /* tp_prev */
    0,                                           /* *tp_next */
#endif
};
#undef _THIS_SIZE1
#undef _THIS_SIZE2
#undef _THIS_DOC

/**end repeat**/


static PyNumberMethods longdoubletype_as_number;
static PyNumberMethods clongdoubletype_as_number;


static void
initialize_numeric_types(void)
{
    PyGenericArrType_Type.tp_dealloc = (destructor)gentype_dealloc;
    PyGenericArrType_Type.tp_as_number = &gentype_as_number;
    PyGenericArrType_Type.tp_as_buffer = &gentype_as_buffer;
    PyGenericArrType_Type.tp_as_mapping = &gentype_as_mapping;
    PyGenericArrType_Type.tp_flags = BASEFLAGS;
    PyGenericArrType_Type.tp_methods = gentype_methods;
    PyGenericArrType_Type.tp_getset = gentype_getsets;
    PyGenericArrType_Type.tp_new = NULL;
    PyGenericArrType_Type.tp_alloc = gentype_alloc;
    PyGenericArrType_Type.tp_free = _pya_free;
    PyGenericArrType_Type.tp_repr = gentype_repr;
    PyGenericArrType_Type.tp_str = gentype_str;
    PyGenericArrType_Type.tp_richcompare = gentype_richcompare;

    PyBoolArrType_Type.tp_as_number = &bool_arrtype_as_number;
#if PY_VERSION_HEX >= 0x02050000
    /*
     * need to add dummy versions with filled-in nb_index
     * in-order for PyType_Ready to fill in .__index__() method
     */
    /**begin repeat
     * #name = byte, short, int, long, longlong, ubyte, ushort,
     *         uint, ulong, ulonglong#
     * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort,
     *         UInt, ULong, ULongLong#
     */
    Py@NAME@ArrType_Type.tp_as_number = &@name@_arrtype_as_number;
    Py@NAME@ArrType_Type.tp_as_number->nb_index = (unaryfunc)@name@_index;

    /**end repeat**/
    PyBoolArrType_Type.tp_as_number->nb_index = (unaryfunc)bool_index;
#endif

    PyStringArrType_Type.tp_alloc = NULL;
    PyStringArrType_Type.tp_free = NULL;

    PyStringArrType_Type.tp_repr = stringtype_repr;
    PyStringArrType_Type.tp_str = stringtype_str;

    PyUnicodeArrType_Type.tp_repr = unicodetype_repr;
    PyUnicodeArrType_Type.tp_str = unicodetype_str;

    PyVoidArrType_Type.tp_methods = voidtype_methods;
    PyVoidArrType_Type.tp_getset = voidtype_getsets;
    PyVoidArrType_Type.tp_as_mapping = &voidtype_as_mapping;
    PyVoidArrType_Type.tp_as_sequence = &voidtype_as_sequence;

    /**begin repeat
     * #NAME= Number, Integer, SignedInteger, UnsignedInteger, Inexact,
     *        Floating, ComplexFloating, Flexible, Character#
     */
    Py@NAME@ArrType_Type.tp_flags = BASEFLAGS;
    /**end repeat**/

    /**begin repeat
     * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint,
     *         ulong, ulonglong, float, double, longdouble, cfloat, cdouble,
     *         clongdouble, string, unicode, void, object#
     * #NAME = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt,
     *         ULong, ULongLong, Float, Double, LongDouble, CFloat, CDouble,
     *         CLongDouble, String, Unicode, Void, Object#
     */
    Py@NAME@ArrType_Type.tp_flags = BASEFLAGS;
    Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new;
    Py@NAME@ArrType_Type.tp_richcompare = gentype_richcompare;
    /**end repeat**/

    /**begin repeat
     * #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong,
     *         float, longdouble, cfloat, clongdouble, void, object#
     * #NAME = Bool, Byte, Short, UByte, UShort, UInt, ULong, ULongLong,
     *         Float, LongDouble, CFloat, CLongDouble, Void, Object#
     */
    Py@NAME@ArrType_Type.tp_hash = @name@_arrtype_hash;
    /**end repeat**/

#if SIZEOF_INT != SIZEOF_LONG
    /* We won't be inheriting from Python Int type. */
    PyIntArrType_Type.tp_hash = int_arrtype_hash;
#endif

#if SIZEOF_LONG != SIZEOF_LONGLONG
    /* We won't be inheriting from Python Int type. */
    PyLongLongArrType_Type.tp_hash = longlong_arrtype_hash;
#endif

    /**begin repeat
     * #name = repr, str#
     */
    PyFloatArrType_Type.tp_@name@ = floattype_@name@;
    PyCFloatArrType_Type.tp_@name@ = cfloattype_@name@;

    PyDoubleArrType_Type.tp_@name@ = doubletype_@name@;
    PyCDoubleArrType_Type.tp_@name@  = cdoubletype_@name@;
    /**end repeat**/

    PyFloatArrType_Type.tp_print = floattype_print;
    PyDoubleArrType_Type.tp_print = doubletype_print;
    PyLongDoubleArrType_Type.tp_print = longdoubletype_print;

    PyCFloatArrType_Type.tp_print = cfloattype_print;
    PyCDoubleArrType_Type.tp_print = cdoubletype_print;
    PyCLongDoubleArrType_Type.tp_print = clongdoubletype_print;

    /*
     * These need to be coded specially because getitem does not
     * return a normal Python type
     */
    PyLongDoubleArrType_Type.tp_as_number = &longdoubletype_as_number;
    PyCLongDoubleArrType_Type.tp_as_number = &clongdoubletype_as_number;

    /**begin repeat
     * #name = int, long, hex, oct, float, repr, str#
     * #kind = tp_as_number->nb*5, tp*2#
     */
    PyLongDoubleArrType_Type.@kind@_@name@ = longdoubletype_@name@;
    PyCLongDoubleArrType_Type.@kind@_@name@ = clongdoubletype_@name@;
    /**end repeat**/

    PyStringArrType_Type.tp_itemsize = sizeof(char);
    PyVoidArrType_Type.tp_dealloc = (destructor) void_dealloc;

    PyArrayIter_Type.tp_iter = PyObject_SelfIter;
    PyArrayMapIter_Type.tp_iter = PyObject_SelfIter;
}


/* the order of this table is important */
static PyTypeObject *typeobjects[] = {
    &PyBoolArrType_Type,
    &PyByteArrType_Type,
    &PyUByteArrType_Type,
    &PyShortArrType_Type,
    &PyUShortArrType_Type,
    &PyIntArrType_Type,
    &PyUIntArrType_Type,
    &PyLongArrType_Type,
    &PyULongArrType_Type,
    &PyLongLongArrType_Type,
    &PyULongLongArrType_Type,
    &PyFloatArrType_Type,
    &PyDoubleArrType_Type,
    &PyLongDoubleArrType_Type,
    &PyCFloatArrType_Type,
    &PyCDoubleArrType_Type,
    &PyCLongDoubleArrType_Type,
    &PyObjectArrType_Type,
    &PyStringArrType_Type,
    &PyUnicodeArrType_Type,
    &PyVoidArrType_Type
};

static int
_typenum_fromtypeobj(PyObject *type, int user)
{
    int typenum, i;

    typenum = PyArray_NOTYPE;
    i = 0;
    while(i < PyArray_NTYPES) {
        if (type == (PyObject *)typeobjects[i]) {
            typenum = i;
            break;
        }
        i++;
    }

    if (!user) {
        return typenum;
    }
    /* Search any registered types */
    i = 0;
    while (i < PyArray_NUMUSERTYPES) {
        if (type == (PyObject *)(userdescrs[i]->typeobj)) {
            typenum = i + PyArray_USERDEF;
            break;
        }
        i++;
    }
    return typenum;
}

static PyArray_Descr *
_descr_from_subtype(PyObject *type)
{
    PyObject *mro;
    mro = ((PyTypeObject *)type)->tp_mro;
    if (PyTuple_GET_SIZE(mro) < 2) {
        return PyArray_DescrFromType(PyArray_OBJECT);
    }
    return PyArray_DescrFromTypeObject(PyTuple_GET_ITEM(mro, 1));
}

/*New reference */
/*NUMPY_API
 */
static PyArray_Descr *
PyArray_DescrFromTypeObject(PyObject *type)
{
    int typenum;
    PyArray_Descr *new, *conv=NULL;

    /* if it's a builtin type, then use the typenumber */
    typenum = _typenum_fromtypeobj(type,1);
    if (typenum != PyArray_NOTYPE) {
        new = PyArray_DescrFromType(typenum);
        return new;
    }

    /* Check the generic types */
    if ((type == (PyObject *) &PyNumberArrType_Type) ||
            (type == (PyObject *) &PyInexactArrType_Type) ||
            (type == (PyObject *) &PyFloatingArrType_Type)) {
        typenum = PyArray_DOUBLE;
    }
    else if (type == (PyObject *)&PyComplexFloatingArrType_Type) {
        typenum = PyArray_CDOUBLE;
    }
    else if ((type == (PyObject *)&PyIntegerArrType_Type) ||
            (type == (PyObject *)&PySignedIntegerArrType_Type)) {
        typenum = PyArray_LONG;
    }
    else if (type == (PyObject *) &PyUnsignedIntegerArrType_Type) {
        typenum = PyArray_ULONG;
    }
    else if (type == (PyObject *) &PyCharacterArrType_Type) {
        typenum = PyArray_STRING;
    }
    else if ((type == (PyObject *) &PyGenericArrType_Type) ||
            (type == (PyObject *) &PyFlexibleArrType_Type)) {
        typenum = PyArray_VOID;
    }

    if (typenum != PyArray_NOTYPE) {
        return PyArray_DescrFromType(typenum);
    }

    /*
     * Otherwise --- type is a sub-type of an array scalar
     * not corresponding to a registered data-type object.
     */

    /* Do special thing for VOID sub-types */
    if (PyType_IsSubtype((PyTypeObject *)type, &PyVoidArrType_Type)) {
        new = PyArray_DescrNewFromType(PyArray_VOID);
        conv = _arraydescr_fromobj(type);
        if (conv) {
            new->fields = conv->fields;
            Py_INCREF(new->fields);
            new->names = conv->names;
            Py_INCREF(new->names);
            new->elsize = conv->elsize;
            new->subarray = conv->subarray;
            conv->subarray = NULL;
            Py_DECREF(conv);
        }
        Py_XDECREF(new->typeobj);
        new->typeobj = (PyTypeObject *)type;
        Py_INCREF(type);
        return new;
    }
    return _descr_from_subtype(type);
}

/*NUMPY_API
 * Return the tuple of ordered field names from a dictionary.
 */
static PyObject *
PyArray_FieldNames(PyObject *fields)
{
    PyObject *tup;
    PyObject *ret;
    PyObject *_numpy_internal;

    if (!PyDict_Check(fields)) {
        PyErr_SetString(PyExc_TypeError,
                "Fields must be a dictionary");
        return NULL;
    }
    _numpy_internal = PyImport_ImportModule("numpy.core._internal");
    if (_numpy_internal == NULL) {
        return NULL;
    }
    tup = PyObject_CallMethod(_numpy_internal, "_makenames_list", "O", fields);
    Py_DECREF(_numpy_internal);
    if (tup == NULL) {
        return NULL;
    }
    ret = PyTuple_GET_ITEM(tup, 0);
    ret = PySequence_Tuple(ret);
    Py_DECREF(tup);
    return ret;
}

/*NUMPY_API
 * Return descr object from array scalar.
 *
 * New reference
 */
static PyArray_Descr *
PyArray_DescrFromScalar(PyObject *sc)
{
    int type_num;
    PyArray_Descr *descr;

    if (PyArray_IsScalar(sc, Void)) {
        descr = ((PyVoidScalarObject *)sc)->descr;
        Py_INCREF(descr);
        return descr;
    }
    descr = PyArray_DescrFromTypeObject((PyObject *)sc->ob_type);
    if (descr->elsize == 0) {
        PyArray_DESCR_REPLACE(descr);
        type_num = descr->type_num;
        if (type_num == PyArray_STRING) {
            descr->elsize = PyString_GET_SIZE(sc);
        }
        else if (type_num == PyArray_UNICODE) {
            descr->elsize = PyUnicode_GET_DATA_SIZE(sc);
#ifndef Py_UNICODE_WIDE
            descr->elsize <<= 1;
#endif
        }
        else {
            descr->elsize =
                ((PyVoidScalarObject *)sc)->ob_size;
            descr->fields = PyObject_GetAttrString(sc, "fields");
            if (!descr->fields || !PyDict_Check(descr->fields) ||
                    (descr->fields == Py_None)) {
                Py_XDECREF(descr->fields);
                descr->fields = NULL;
            }
            if (descr->fields) {
                descr->names = PyArray_FieldNames(descr->fields);
            }
            PyErr_Clear();
        }
    }
    return descr;
}

/*NUMPY_API
 * Get a typeobject from a type-number -- can return NULL.
 *
 * New reference
 */
static PyObject *
PyArray_TypeObjectFromType(int type)
{
    PyArray_Descr *descr;
    PyObject *obj;

    descr = PyArray_DescrFromType(type);
    if (descr == NULL) {
        return NULL;
    }
    obj = (PyObject *)descr->typeobj;
    Py_XINCREF(obj);
    Py_DECREF(descr);
    return obj;
}
